Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>(fnThisType));
}
}
}
if (parent == null) {
codingConvention.defineDelegateProxyPrototypeProperties(
typeRegistry, newScope, delegateProxyPrototypes,
delegateCallingConventions);
}
return newScope;
}
/**
* Patches a given global scope by removing variables previously declared in
* a script and re-traversing a new version of that script.
*
* @param globalScope The global scope generated by {@code createScope}.
* @param scriptRoot The script that is modified.
*/
void patchGlobalScope(Scope globalScope, Node scriptRoot) {
// Preconditions: This is supposed to be called only on (named) SCRIPT nodes
// and a global typed scope should have been generated already.
Preconditions.checkState(scriptRoot.isScript());
Preconditions.checkNotNull(globalScope);
Preconditions.checkState(globalScope.isGlobal());
String scriptName = NodeUtil.getSourceName(scriptRoot);
Preconditions.checkNotNull(scriptName);
for (Node node : ImmutableList.copyOf(functionAnalysisResults.keySet())) {
if (scriptName.equals(NodeUtil.getSourceName(node))) {
functionAnalysisResults.remove(node);
}
}
(new FirstOrderFunctionAnalyzer(
compiler, functionAnalysisResults)).process(null, scriptRoot);
// TODO(bashir): Variable declaration is not the only side effect of last
// global scope generation but here we only wipe that part off!
// Remove all variables that were previously declared in this scripts.
// First find all vars to remove then remove them because of iterator!
Iterator<Var> varIter = globalScope.getVars();
List<Var> varsToRemove = Lists.newArrayList();
while (varIter.hasNext()) {
Var oldVar = varIter.next();
if (scriptName.equals(oldVar.getInputName())) {
varsToRemove.add(oldVar);
}
}
for (Var var : varsToRemove) {
globalScope.undeclare(var);
globalScope.getTypeOfThis().removeProperty(var.getName());
}
// Now re-traverse the given script.
GlobalScopeBuilder scopeBuilder = new GlobalScopeBuilder(globalScope);
NodeTraversal.traverse(compiler, scriptRoot, scopeBuilder);
}
/**
* Create the outermost
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>, null, false);
}
private static class DiscoverEnumsAndTypedefs
extends AbstractShallowStatementCallback {
private final JSTypeRegistry registry;
DiscoverEnumsAndTypedefs(JSTypeRegistry registry) {
this.registry = registry;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
Node nameNode = null;
switch (node.getType()) {
case Token.VAR:
for (Node child = node.getFirstChild();
child != null; child = child.getNext()) {
identifyNameNode(
child, child.getFirstChild(),
NodeUtil.getBestJSDocInfo(child));
}
break;
case Token.EXPR_RESULT:
Node firstChild = node.getFirstChild();
if (firstChild.isAssign()) {
identifyNameNode(
firstChild.getFirstChild(), firstChild.getLastChild(),
firstChild.getJSDocInfo());
} else {
identifyNameNode(
firstChild, null, firstChild.getJSDocInfo());
}
break;
}
}
private void identifyNameNode(
Node nameNode, Node valueNode, JSDocInfo info) {
if (nameNode.isQualifiedName()) {
if (info != null) {
if (info.hasEnumParameterType()) {
registry.identifyNonNullableName(nameNode.getQualifiedName());
} else if (info.hasTypedefType()) {
registry.identifyNonNullableName(nameNode.getQualifiedName());
}
}
}
}
}
private JSType getNativeType(JSTypeNative nativeType) {
return typeRegistry.getNativeType(nativeType);
}
private abstract class AbstractScopeBuilder
implements NodeTraversal.Callback {
/**
* The scope that we're builidng.
/**
* The InputId of the current node.
*/
private InputId inputId;
private AbstractScopeBuilder(Scope scope) {
this.scope = scope;
}
void setDeferredType(Node node, JSType type) {
deferredSetTypes.add(new DeferredSetType(node, type));
}
void resolveTypes() {
// Resolve types and attach them to nodes.
for (DeferredSetType deferred : deferredSetTypes) {
deferred.resolve(scope);
}
//
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> Resolve types and attach them to scope slots.
Iterator<Var> vars = scope.getVars();
while (vars.hasNext()) {
vars.next().resolveType(typeParsingErrorReporter);
}
// Tell the type registry that any remaining types
// are unknown.
typeRegistry.resolveTypesInScope(scope);
}
@Override
public final boolean shouldTraverse(NodeTraversal t, Node n,
Node parent) {
inputId = t.getInputId();
if (n.isFunction() ||
n.isScript()) {
Preconditions.checkNotNull(inputId);
sourceName = NodeUtil.getSourceName(n);
}
// We do want to traverse the name of a named function, but we don't
// want to traverse the arguments or body.
boolean descend = parent == null || !parent.isFunction() ||
n == parent.getFirstChild() || parent == scope.getRootNode();
if (descend) {
// Handle hoisted functions on pre-order traversal, so that they
// get hit before other things in the scope.
if (NodeUtil.isStatementParent(n)) {
for (Node child = n.getFirstChild();
child != null;
child = child.getNext()) {
if (NodeUtil.isHoistedFunctionDeclaration(child)) {
defineFunctionLiteral(child, n);
}
}
}
}
return descend;
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
inputId = t.getInputId();
attachLiteralTypes(t, n);
switch (n.getType()) {
case Token.CALL:
checkForClassDefiningCalls(t, n, parent);
checkForCallingConventionDefiningCalls(n, delegateCallingConventions);
break;
case Token.FUNCTION:
if (t.getInput() == null || !t.getInput().isExtern()) {
nonExternFunctions.add(n);
}
// Hoisted functions are handled during pre-traversal.
if (!NodeUtil.isHoistedFunctionDeclaration(n)) {
defineFunctionLiteral(n, parent);
}
break;
case Token.ASSIGN:
// Handle initialization of properties.
Node firstChild = n.getFirstChild();
if (firstChild.isGetProp() &&
firstChild.
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(),
Var lendsVar = scope.getVar(lendsName);
if (lendsVar == null) {
compiler.report(
JSError.make(sourceName, objectLit, UNKNOWN_LENDS, lendsName));
} else {
type = lendsVar.getType();
if (type == null) {
type = typeRegistry.getNativeType(UNKNOWN_TYPE);
}
if (!type.isSubtype(typeRegistry.getNativeType(OBJECT_TYPE))) {
compiler.report(
JSError.make(sourceName, objectLit, LENDS_ON_NON_OBJECT,
lendsName, type.toString()));
type = null;
} else {
objectLit.setJSType(type);
}
}
}
info = NodeUtil.getBestJSDocInfo(objectLit);
Node lValue = NodeUtil.getBestLValue(objectLit);
String lValueName = NodeUtil.getBestLValueName(lValue);
boolean createdEnumType = false;
if (info != null && info.hasEnumParameterType()) {
type = createEnumTypeFromNodes(objectLit, lValueName, info, lValue);
createdEnumType = true;
}
if (type == null) {
type = typeRegistry.createAnonymousObjectType();
}
setDeferredType(objectLit, type);
// If this is an enum, the properties were already taken care of above.
processObjectLitProperties(
objectLit, ObjectType.cast(objectLit.getJSType()), !createdEnumType);
}
/**
* Process an object literal and all the types on it.
* @param objLit The OBJECTLIT node.
* @param objLitType The type of the OBJECTLIT node. This might be a named
* type, because of the lends annotation.
* @param declareOnOwner If true, declare properties on the objLitType as
* well. If false, the caller should take crae of this.
*/
void processObjectLitProperties(
Node objLit, ObjectType objLitType,
boolean declareOnOwner) {
for (Node keyNode = objLit.getFirstChild(); keyNode != null;
keyNode = keyNode
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>.getNext()) {
Node value = keyNode.getFirstChild();
String memberName = NodeUtil.getObjectLitKeyName(keyNode);
JSDocInfo info = keyNode.getJSDocInfo();
JSType valueType =
getDeclaredType(keyNode.getSourceFileName(), info, keyNode, value);
JSType keyType = objLitType.isEnumType() ?
objLitType.toMaybeEnumType().getElementsType() :
NodeUtil.getObjectLitKeyTypeFromValueType(keyNode, valueType);
// Try to declare this property in the current scope if it
// has an authoritative name.
String qualifiedName = NodeUtil.getBestLValueName(keyNode);
if (qualifiedName != null) {
boolean inferred = keyType == null;
defineSlot(keyNode, objLit, qualifiedName, keyType, inferred);
} else if (keyType != null) {
setDeferredType(keyNode, keyType);
}
if (keyType != null && objLitType != null && declareOnOwner) {
// Declare this property on its object literal.
boolean isExtern = keyNode.isFromExterns();
objLitType.defineDeclaredProperty(memberName, keyType, keyNode);
}
}
}
/**
* Returns the type specified in a JSDoc annotation near a GETPROP or NAME.
*
* Extracts type information from either the {@code @type} tag or from
* the {@code @return} and {@code @param} tags.
*/
private JSType getDeclaredTypeInAnnotation(String sourceName,
Node node, JSDocInfo info) {
JSType jsType = null;
Node objNode =
node.isGetProp() ? node.getFirstChild() :
NodeUtil.isObjectLitKey(node, node.getParent()) ? node.getParent() :
null;
if (info != null) {
if (info.hasType()) {
jsType = info.getType().evaluate(scope, typeRegistry);
} else if (FunctionTypeBuilder.isFunctionTypeDeclaration(info)) {
String fnName = node.getQualifiedName();
jsType = createFunctionTypeFromNodes(
null, fnName, info, node);
}
}
return jsType;
}
/**
* Asserts that it
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Type delegateProxy = typeRegistry.createConstructorType(
delegateBaseObject.getReferenceName() + DELEGATE_PROXY_SUFFIX,
null, null, null);
delegateProxy.setPrototypeBasedOn(delegateBaseObject);
codingConvention.applyDelegateRelationship(
delegateSuperObject, delegateBaseObject, delegatorObject,
delegateProxy, findDelegate);
delegateProxyPrototypes.add(delegateProxy.getPrototype());
}
}
}
/**
* Declare the symbol for a qualified name in the global scope.
*
* @param info The doc info for this property.
* @param n A top-level GETPROP node (it should not be contained inside
* another GETPROP).
* @param parent The parent of {@code n}.
* @param rhsValue The node that {@code n} is being initialized to,
* or {@code null} if this is a stub declaration.
*/
void maybeDeclareQualifiedName(NodeTraversal t, JSDocInfo info,
Node n, Node parent, Node rhsValue) {
Node ownerNode = n.getFirstChild();
String ownerName = ownerNode.getQualifiedName();
String qName = n.getQualifiedName();
String propName = n.getLastChild().getString();
Preconditions.checkArgument(qName != null && ownerName != null);
// Precedence of type information on GETPROPs:
// 1) @type annnotation / @enum annotation
// 2) ASSIGN to FUNCTION literal
// 3) @param/@return annotation (with no function literal)
// 4) ASSIGN to something marked @const
// 5) ASSIGN to anything else
//
// 1, 3, and 4 are declarations, 5 is inferred, and 2 is a declaration iff
// the function has jsdoc or has not been declared before.
//
// FUNCTION literals are special because TypedScopeCreator is very smart
// about getting as much type information as possible for them.
// Determining type for #1 + #2 + #3 + #4
JSType valueType = getDeclaredType(t.getSourceName(), info, n, rhsValue);
if (valueType == null && rhsValue != null) {
// Determining type for #5
valueType = rhsValue.getJSType();
}
// Function prototypes are special
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>.
// It's a common JS idiom to do:
// F.prototype = { ... };
// So if F does not have an explicitly declared super type,
// allow F.prototype to be redefined arbitrarily.
if ("prototype".equals(propName)) {
Var qVar = scope.getVar(qName);
if (qVar != null) {
// If the programmer has declared that F inherits from Super,
// and they assign F.prototype to an object literal,
// then they are responsible for making sure that the object literal's
// implicit prototype is set up appropriately. We just obey
// the @extends tag.
ObjectType qVarType = ObjectType.cast(qVar.getType());
if (qVarType != null &&
rhsValue != null &&
rhsValue.isObjectLit()) {
typeRegistry.resetImplicitPrototype(
rhsValue.getJSType(), qVarType.getImplicitPrototype());
} else if (!qVar.isTypeInferred()) {
// If the programmer has declared that F inherits from Super,
// and they assign F.prototype to some arbitrary expression,
// there's not much we can do. We just ignore the expression,
// and hope they've annotated their code in a way to tell us
// what props are going to be on that prototype.
return;
}
if (qVar.getScope() == scope) {
scope.undeclare(qVar);
}
}
}
if (valueType == null) {
if (parent.isExprResult()) {
stubDeclarations.add(new StubDeclaration(
n,
t.getInput() != null && t.getInput().isExtern(),
ownerName));
}
return;
}
boolean inferred = isQualifiedNameInferred(
qName, n, info, rhsValue, valueType);
if (!inferred) {
ObjectType ownerType = getObjectSlot(ownerName);
if (ownerType != null) {
// Only declare this as an official property if it has not been
// declared yet.
boolean isExtern = t.getInput() != null && t.getInput().isExtern();
if ((!ownerType.hasOwnProperty(propName) ||
ownerType.isPropertyTypeInferred(propName)) &&
((isExtern && !ownerType.isNativeObjectType()) ||
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> t.getScope().getVar(name);
if (isConstant(var)) {
if (initializedConstants.contains(var)) {
reportError(t, n, name);
} else {
initializedConstants.add(var);
}
}
}
break;
case Token.ASSIGN:
case Token.ASSIGN_BITOR:
case Token.ASSIGN_BITXOR:
case Token.ASSIGN_BITAND:
case Token.ASSIGN_LSH:
case Token.ASSIGN_RSH:
case Token.ASSIGN_URSH:
case Token.ASSIGN_ADD:
case Token.ASSIGN_SUB:
case Token.ASSIGN_MUL:
case Token.ASSIGN_DIV:
case Token.ASSIGN_MOD: {
Node lhs = n.getFirstChild();
if (lhs.isName()) {
String name = lhs.getString();
Scope.Var var = t.getScope().getVar(name);
if (isConstant(var)) {
if (initializedConstants.contains(var)) {
reportError(t, n, name);
} else {
initializedConstants.add(var);
}
}
}
break;
}
case Token.INC:
case Token.DEC: {
Node lhs = n.getFirstChild();
if (lhs.isName()) {
String name = lhs.getString();
Scope.Var var = t.getScope().getVar(name);
if (isConstant(var)) {
reportError(t, n, name);
}
}
break;
}
}
}
/**
* Gets whether a variable is a constant initialized to a literal value at
* the point where it is declared.
*/
private boolean isConstant(Scope.Var var) {
return var != null && var.isConst();
}
/**
* Reports a reassigned constant error.
*/
void reportError(NodeTraversal t, Node n, String name) {
compiler.report(t.makeError(n, CONST_REASSIGNED_VALUE_ERROR, name));
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> else
break;
}
}
} else if (pt != Token.EXPR_RESULT && pt != Token.BLOCK) {
if (pt == Token.FOR && parent.getChildCount() == 4 &&
(n == parent.getFirstChild() ||
n == parent.getFirstChild().getNext().getNext())) {
// Fall through and look for warnings for the 1st and 3rd child
// of a for.
} else {
return; // it might be ok to not have a side-effect
}
}
boolean isSimpleOp = NodeUtil.isSimpleOperatorType(n.getType());
if (isSimpleOp ||
!NodeUtil.mayHaveSideEffects(n, t.getCompiler())) {
if (n.isQualifiedName() && n.getJSDocInfo() != null) {
// This no-op statement was there so that JSDoc information could
// be attached to the name. This check should not complain about it.
return;
} else if (n.isExprResult()) {
// we already reported the problem when we visited the child.
return;
}
String msg = "This code lacks side-effects. Is there a bug?";
if (n.isString()) {
msg = "Is there a missing '+' on the previous line?";
} else if (isSimpleOp) {
msg = "The result of the '" + Token.name(n.getType()).toLowerCase() +
"' operator is not being used.";
}
t.getCompiler().report(
t.makeError(n, level, USELESS_CODE_ERROR, msg));
// TODO(johnlenz): determine if it is necessary to
// try to protect side-effect free statements as well.
if (!NodeUtil.isStatement(n)) {
problemNodes.add(n);
}
}
}
/**
* Protect side-effect free nodes by making them parameters
* to a extern function call. This call will be removed
* after all the optimizations passes have run.
*/
private void protectSideEffects() {
if (!problemNodes.isEmpty()) {
addExtern();
for (Node n : problemNodes) {
Node name = IR.name(PROTECTOR_FN).srcref(n);
name.putBooleanProp(
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> LinkedDirectedGraph<N, E>(true, false);
}
public static <N, E> LinkedDirectedGraph<N, E> createWithEdgeAnnotations() {
return new LinkedDirectedGraph<N, E>(false, true);
}
public static <N, E> LinkedDirectedGraph<N, E> create() {
return new LinkedDirectedGraph<N, E>(true, true);
}
private final boolean useNodeAnnotations;
private final boolean useEdgeAnnotations;
protected LinkedDirectedGraph(
boolean useNodeAnnotations, boolean useEdgeAnnotations) {
this.useNodeAnnotations = useNodeAnnotations;
this.useEdgeAnnotations = useEdgeAnnotations;
}
@Override
public void connect(N srcValue, E edgeValue, N destValue) {
LinkedDirectedGraphNode<N, E> src = getNodeOrFail(srcValue);
LinkedDirectedGraphNode<N, E> dest = getNodeOrFail(destValue);
LinkedDirectedGraphEdge<N, E> edge =
useEdgeAnnotations ?
new AnnotatedLinkedDirectedGraphEdge<N, E>(src, edgeValue, dest) :
new LinkedDirectedGraphEdge<N, E>(src, edgeValue, dest);
src.getOutEdges().add(edge);
dest.getInEdges().add(edge);
}
@Override
public void disconnect(N n1, N n2) {
disconnectInDirection(n1, n2);
disconnectInDirection(n2, n1);
}
@Override
public void disconnectInDirection(N srcValue, N destValue) {
LinkedDirectedGraphNode<N, E> src = getNodeOrFail(srcValue);
LinkedDirectedGraphNode<N, E> dest = getNodeOrFail(destValue);
for (DiGraphEdge<?, E> edge : getDirectedGraphEdges(srcValue, destValue)) {
src.getOutEdges().remove(edge);
dest.getInEdges().remove(edge);
}
}
@Override
public Iterable<DiGraphNode<N, E>> getDirectedGraphNodes() {
return Collections.<DiGraphNode<N, E>>unmodifiableCollection(
nodes.values());
}
@Override
public DiGraphNode<N, E> getDirectedGraphNode(N nodeValue) {
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>);
for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) {
if (outEdge.getDestination() == dNode2) {
return outEdge;
}
}
for (DiGraphEdge<N, E> outEdge : dNode2.getOutEdges()) {
if (outEdge.getDestination() == dNode1) {
return outEdge;
}
}
return null;
}
@Override
public GraphNode<N, E> createNode(N value) {
return createDirectedGraphNode(value);
}
@Override
public List<DiGraphEdge<N, E>> getDirectedGraphEdges(N n1, N n2) {
DiGraphNode<N, E> dNode1 = getNodeOrFail(n1);
DiGraphNode<N, E> dNode2 = getNodeOrFail(n2);
List<DiGraphEdge<N, E>> edges = Lists.newArrayList();
for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) {
if (outEdge.getDestination() == dNode2) {
edges.add(outEdge);
}
}
return edges;
}
@Override
public boolean isConnectedInDirection(N n1, N n2) {
return isConnectedInDirection(n1, Predicates.<E>alwaysTrue(), n2);
}
@Override
public boolean isConnectedInDirection(N n1, E edgeValue, N n2) {
return isConnectedInDirection(n1, Predicates.equalTo(edgeValue), n2);
}
private boolean isConnectedInDirection(N n1, Predicate<E> edgeMatcher, N n2) {
// Verify the nodes.
DiGraphNode<N, E> dNode1 = getNodeOrFail(n1);
DiGraphNode<N, E> dNode2 = getNodeOrFail(n2);
for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) {
if (outEdge.getDestination() == dNode2 &&
edgeMatcher.apply(outEdge.getValue())) {
return true;
}
}
return false;
}
@Override
public List<DiGraphNode<N, E>>
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> getDirectedPredNodes(N nodeValue) {
return getDirectedPredNodes(nodes.get(nodeValue));
}
@Override
public List<DiGraphNode<N, E>> getDirectedSuccNodes(N nodeValue) {
return getDirectedSuccNodes(nodes.get(nodeValue));
}
@Override
public List<DiGraphNode<N, E>> getDirectedPredNodes(
DiGraphNode<N, E> dNode) {
if (dNode == null) {
throw new IllegalArgumentException(dNode + " is null");
}
List<DiGraphNode<N, E>> nodeList = Lists.newArrayList();
for (DiGraphEdge<N, E> edge : dNode.getInEdges()) {
nodeList.add(edge.getSource());
}
return nodeList;
}
@Override
public List<DiGraphNode<N, E>> getDirectedSuccNodes(
DiGraphNode<N, E> dNode) {
if (dNode == null) {
throw new IllegalArgumentException(dNode + " is null");
}
List<DiGraphNode<N, E>> nodeList = Lists.newArrayList();
for (DiGraphEdge<N, E> edge : dNode.getOutEdges()) {
nodeList.add(edge.getDestination());
}
return nodeList;
}
@Override
public List<GraphvizEdge> getGraphvizEdges() {
List<GraphvizEdge> edgeList = Lists.newArrayList();
for (LinkedDirectedGraphNode<N, E> node : nodes.values()) {
for (DiGraphEdge<N, E> edge : node.getOutEdges()) {
edgeList.add((LinkedDirectedGraphEdge<N, E>) edge);
}
}
return edgeList;
}
@Override
public List<GraphvizNode> getGraphvizNodes() {
List<GraphvizNode> nodeList =
Lists.newArrayListWithCapacity(nodes.size());
for (LinkedDirectedGraphNode<N, E> node : nodes.values()) {
nodeList.add(node);
}
return nodeList;
}
@Override
public String getName() {
return "LinkedGraph";
}
@Override
public boolean isDirected() {
return
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> true;
}
@Override
public Collection<GraphNode<N, E>> getNodes() {
return Collections.<GraphNode<N, E>>unmodifiableCollection(nodes.values());
}
@Override
public List<GraphNode<N, E>> getNeighborNodes(N value) {
DiGraphNode<N, E> node = getDirectedGraphNode(value);
return getNeighborNodes(node);
}
public List<GraphNode<N, E>> getNeighborNodes(DiGraphNode<N, E> node) {
List<GraphNode<N, E>> result = Lists.newArrayList();
for (Iterator<GraphNode<N, E>> i =
((LinkedDirectedGraphNode<N, E>) node).neighborIterator();i.hasNext();) {
result.add(i.next());
}
return result;
}
@Override
public Iterator<GraphNode<N, E>> getNeighborNodesIterator(N value) {
LinkedDirectedGraphNode<N, E> node = nodes.get(value);
Preconditions.checkNotNull(node);
return node.neighborIterator();
}
@Override
public List<GraphEdge<N, E>> getEdges() {
List<GraphEdge<N, E>> result = Lists.newArrayList();
for (DiGraphNode<N, E> node : nodes.values()) {
for (DiGraphEdge<N, E> edge : node.getOutEdges()) {
result.add(edge);
}
}
return Collections.unmodifiableList(result);
}
@Override
public int getNodeDegree(N value) {
DiGraphNode<N, E> node = getNodeOrFail(value);
return node.getInEdges().size() + node.getOutEdges().size();
}
/**
* A directed graph node that stores outgoing edges and incoming edges as an
* list within the node itself.
*/
static class LinkedDirectedGraphNode<N, E> implements DiGraphNode<N, E>,
GraphvizNode {
List<DiGraphEdge<N, E>> inEdgeList = Lists.newArrayList();
List<DiGraphEdge<N, E>> outEdgeList =
Lists.newArrayList();
protected final N value;
/**
* Constructor
*
* @param nodeValue Node's value.
*/
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> {
return createConfig(isIdeMode, languageMode, acceptConstKeyword, null);
}
public static Config createConfig(boolean isIdeMode,
LanguageMode languageMode,
boolean acceptConstKeyword,
Set<String> extraAnnotationNames) {
initResourceConfig();
Set<String> effectiveAnnotationNames;
if (extraAnnotationNames == null) {
effectiveAnnotationNames = annotationNames;
} else {
effectiveAnnotationNames = new HashSet<String>(annotationNames);
effectiveAnnotationNames.addAll(extraAnnotationNames);
}
return new Config(effectiveAnnotationNames, suppressionNames,
isIdeMode, languageMode, acceptConstKeyword);
}
private static synchronized void initResourceConfig() {
if (annotationNames != null) {
return;
}
ResourceBundle config = ResourceBundle.getBundle(configResource);
annotationNames = extractList(config.getString("jsdoc.annotations"));
suppressionNames = extractList(config.getString("jsdoc.suppressions"));
}
private static Set<String> extractList(String configProp) {
String[] names = configProp.split(",");
Set<String> trimmedNames = Sets.newHashSet();
for (String name : names) {
trimmedNames.add(name.trim());
}
return ImmutableSet.copyOf(trimmedNames);
}
/**
* Parses the JavaScript text given by a reader.
*
* @param sourceString Source code from the file.
* @param errorReporter An error.
* @param logger A logger.
* @return The AST of the given text.
* @throws IOException
*/
public static Node parse(StaticSourceFile sourceFile,
String sourceString,
Config config,
ErrorReporter errorReporter,
Logger logger) throws IOException {
Context cx = Context.enter();
cx.setErrorReporter(errorReporter);
cx.setLanguageVersion(Context.VERSION_1_5);
CompilerEnvirons compilerEnv = new CompilerEnvirons();
compilerEnv.initFromContext(cx);
compilerEnv.setRecordingComments(true);
compilerEnv.setRecordingLocalJsDocComments(true);
// ES5 specifically allows trailing commas
compilerEnv.setWarnTrailingComma(
config.languageMode == LanguageMode.ECMASCRIPT3);
// Do our own identifier check for ECMASCRIPT 5
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>(instance, implementedInterface,
report(JSError.make(sourceName, n,
INTERFACE_METHOD_NOT_IMPLEMENTED,
prop, implementedInterface.toString(), instance.toString())));
} else {
JSType found = instance.getPropertyType(prop);
JSType required
= implementedInterface.getImplicitPrototype().getPropertyType(prop);
found = found.restrictByNotNullOrUndefined();
required = required.restrictByNotNullOrUndefined();
if (!found.canAssignTo(required)) {
// Implemented, but not correctly typed
FunctionType constructor
= implementedInterface.toObjectType().getConstructor();
registerMismatch(found, required, report(t.makeError(n,
HIDDEN_INTERFACE_PROPERTY_MISMATCH, prop,
constructor.getTopMostDefiningType(prop).toString(),
required.toString(), found.toString())));
}
}
}
/**
* Report a type mismatch
*/
private void mismatch(NodeTraversal t, Node n,
String msg, JSType found, JSType required) {
mismatch(t.getSourceName(), n, msg, found, required);
}
private void mismatch(NodeTraversal t, Node n,
String msg, JSType found, JSTypeNative required) {
mismatch(t, n, msg, found, getNativeType(required));
}
private void mismatch(String sourceName, Node n,
String msg, JSType found, JSType required) {
registerMismatch(found, required, report(
JSError.make(sourceName, n, TYPE_MISMATCH_WARNING,
formatFoundRequired(msg, found, required))));
}
private void registerMismatch(JSType found, JSType required, JSError error) {
// Don't register a mismatch for differences in null or undefined or if the
// code didn't downcast.
found = found.restrictByNotNullOrUndefined();
required = required.restrictByNotNullOrUndefined();
if (found.canAssignTo(required) || required.canAssignTo(found)) {
return;
}
mismatches.add(new TypeMismatch(found, required, error));
if (found.isFunctionType() &&
required.isFunctionType()) {
FunctionType fnTypeA = found.toMaybeFunctionType();
FunctionType fnTypeB = required.toMaybeFunctionType();
Iterator<Node>
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> List<Name> allDefines = Lists.newArrayList();
for (Name name : namespace.getNameIndex().values()) {
Ref decl = name.getDeclaration();
if (name.docInfo != null && name.docInfo.isDefine()) {
// Process defines should not depend on check types being enabled,
// so we look for the JSDoc instead of the inferred type.
if (isValidDefineType(name.docInfo.getType())) {
allDefines.add(name);
} else {
JSError error = JSError.make(
decl.getSourceName(),
decl.node, INVALID_DEFINE_TYPE_ERROR);
compiler.report(error);
}
} else {
for (Ref ref : name.getRefs()) {
if (ref == decl) {
// Declarations were handled above.
continue;
}
Node n = ref.node;
Node parent = ref.node.getParent();
JSDocInfo info = n.getJSDocInfo();
if (info == null &&
parent.isVar() && parent.hasOneChild()) {
info = parent.getJSDocInfo();
}
if (info != null && info.isDefine()) {
allDefines.add(name);
break;
}
}
}
}
CollectDefines pass = new CollectDefines(compiler, allDefines);
NodeTraversal.traverse(compiler, root, pass);
return pass.getAllDefines();
}
/**
* Finds all assignments to @defines, and figures out the last value of
* the @define.
*/
private static final class CollectDefines implements Callback {
private final AbstractCompiler compiler;
private final Map<String, DefineInfo> assignableDefines;
private final Map<String, DefineInfo> allDefines;
private final Map<Node, RefInfo> allRefInfo;
// A hack that allows us to remove ASSIGN/VAR statements when
// we're currently visiting one of the children of the assign.
private Node lvalueToRemoveLater = null;
// A stack tied to the node traversal, to keep track of whether
// we're in a conditional block. If 1 is at the top, assignment to
// a define is allowed. Otherwise, it's not allowed.
private final Deque<Integer> assignAllowed;
CollectDefines(AbstractCompiler compiler, List<
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> are not. But this would be overkill, expecially because
// the intended use of defines is with config_files, where
// all the defines are at the top of the bundle.
for (DefineInfo info : assignableDefines.values()) {
setDefineInfoNotAssignable(info, t);
}
assignableDefines.clear();
}
}
updateAssignAllowedStack(n, false);
}
/**
* Determines whether assignment to a define should be allowed
* in the subtree of the given node, and if not, records that fact.
*
* @param n The node whose subtree we're about to enter or exit.
* @param entering True if we're entering the subtree, false otherwise.
*/
private void updateAssignAllowedStack(Node n, boolean entering) {
switch (n.getType()) {
case Token.CASE:
case Token.FOR:
case Token.FUNCTION:
case Token.HOOK:
case Token.IF:
case Token.SWITCH:
case Token.WHILE:
if (entering) {
assignAllowed.push(0);
} else {
assignAllowed.remove();
}
break;
}
}
/**
* Determines whether assignment to a define should be allowed
* at the current point of the traversal.
*/
private boolean isAssignAllowed() {
return assignAllowed.element() == 1;
}
/**
* Tracks the given define.
*
* @param t The current traversal, for context.
* @param name The full name for this define.
* @param value The value assigned to the define.
* @param valueParent The parent node of value.
* @return Whether we should remove this assignment from the parse tree.
*/
private boolean processDefineAssignment(NodeTraversal t,
String name, Node value, Node valueParent) {
if (value == null || !NodeUtil.isValidDefineValue(value,
allDefines.keySet())) {
compiler.report(
t.makeError(value, INVALID_DEFINE_INIT_ERROR, name));
} else if (!isAssignAllowed()) {
compiler.report(
t.makeError(valueParent, NON_GLOBAL_DEFINE_INIT_ERROR, name));
} else {
DefineInfo info = allDefines.get(name);
if (info == null)
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> computation for an edge case. This seems to be
// a "good enough" approximation.
// conditionOutcomes is cached from previous iterations
// of the loop.
if (conditionOutcomes == null) {
conditionOutcomes = condition.isAnd() ?
traverseAnd(condition, output.createChildFlowScope()) :
traverseOr(condition, output.createChildFlowScope());
}
newScope =
reverseInterpreter.getPreciserScopeKnowingConditionOutcome(
condition,
conditionOutcomes.getOutcomeFlowScope(
condition.getType(), branch == Branch.ON_TRUE),
branch == Branch.ON_TRUE);
} else {
// conditionFlowScope is cached from previous iterations
// of the loop.
if (conditionFlowScope == null) {
conditionFlowScope =
traverse(condition, output.createChildFlowScope());
}
newScope =
reverseInterpreter.getPreciserScopeKnowingConditionOutcome(
condition, conditionFlowScope, branch == Branch.ON_TRUE);
}
}
break;
}
result.add(newScope.optimize());
}
return result;
}
private FlowScope traverse(Node n, FlowScope scope) {
switch (n.getType()) {
case Token.ASSIGN:
scope = traverseAssign(n, scope);
break;
case Token.NAME:
scope = traverseName(n, scope);
break;
case Token.GETPROP:
scope = traverseGetProp(n, scope);
break;
case Token.AND:
scope = traverseAnd(n, scope).getJoinedFlowScope()
.createChildFlowScope();
break;
case Token.OR:
scope = traverseOr(n, scope).getJoinedFlowScope()
.createChildFlowScope();
break;
case Token.HOOK:
scope = traverseHook(n, scope);
break;
case Token.OBJECTLIT:
scope = traverseObjectLiteral(n, scope);
break;
case Token.CALL:
scope = traverseCall(n, scope);
break;
case Token.NEW:
scope = traverseNew(n, scope);
break;
case Token.ASSIGN_ADD:
case Token.ADD:
scope = traverseAdd(n, scope);
break;
case Token.POS:
case Token.NEG:
scope
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>
while (it.hasNext()) {
scope = scopeCreator.createScope(it.next(), scope);
scopes.push(scope);
}
scopeRoots.clear();
return scope;
}
/** Gets the control flow graph for the current JS scope. */
public ControlFlowGraph<Node> getControlFlowGraph() {
if (cfgs.peek() == null) {
ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, true);
cfa.process(null, getScopeRoot());
cfgs.pop();
cfgs.push(cfa.getCfg());
}
return cfgs.peek();
}
/** Returns the current scope's root. */
public Node getScopeRoot() {
if (scopeRoots.isEmpty()) {
return scopes.peek().getRootNode();
} else {
return scopeRoots.peek();
}
}
/**
* Determines whether the traversal is currently in the global scope.
*/
boolean inGlobalScope() {
return getScopeDepth() <= 1;
}
int getScopeDepth() {
return scopes.size() + scopeRoots.size();
}
public boolean hasScope() {
return !(scopes.isEmpty() && scopeRoots.isEmpty());
}
/** Reports a diagnostic (error or warning) */
public void report(Node n, DiagnosticType diagnosticType,
String... arguments) {
JSError error = JSError.make(getSourceName(), n, diagnosticType, arguments);
compiler.report(error);
}
private static String getSourceName(Node n) {
String name = n.getSourceFileName();
return name == null ? "" : name;
}
InputId getInputId() {
return inputId;
}
/**
* Creates a JSError during NodeTraversal.
*
* @param n Determines the line and char position within the source file name
* @param type The DiagnosticType
* @param arguments Arguments to be incorporated into the message
*/
public JSError makeError(Node n, CheckLevel level, DiagnosticType type,
String... arguments) {
return JSError.make(getSourceName(), n, level, type, arguments);
}
/**
* Creates a JSError during NodeTraversal.
*
* @param n Determines the line and char position within the source file name
* @
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>);
}
public static Node hook(Node cond, Node trueval, Node falseval) {
Preconditions.checkState(mayBeExpression(cond));
Preconditions.checkState(mayBeExpression(trueval));
Preconditions.checkState(mayBeExpression(falseval));
return new Node(Token.HOOK, cond, trueval, falseval);
}
public static Node comma(Node expr1, Node expr2) {
return binaryOp(Token.COMMA, expr1, expr2);
}
public static Node and(Node expr1, Node expr2) {
return binaryOp(Token.AND, expr1, expr2);
}
public static Node or(Node expr1, Node expr2) {
return binaryOp(Token.OR, expr1, expr2);
}
public static Node not(Node expr1) {
return unaryOp(Token.NOT, expr1);
}
/**
* "=="
*/
public static Node eq(Node expr1, Node expr2) {
return binaryOp(Token.EQ, expr1, expr2);
}
/**
* "==="
*/
public static Node sheq(Node expr1, Node expr2) {
return binaryOp(Token.SHEQ, expr1, expr2);
}
public static Node voidNode(Node expr1) {
return unaryOp(Token.VOID, expr1);
}
public static Node neg(Node expr1) {
return unaryOp(Token.NEG, expr1);
}
public static Node pos(Node expr1) {
return unaryOp(Token.POS, expr1);
}
public static Node add(Node expr1, Node expr2) {
return binaryOp(Token.ADD, expr1, expr2);
}
public static Node sub(Node expr1, Node expr2) {
return binaryOp(Token.SUB, expr1, expr2);
}
// TODO(johnlenz): the rest of the ops
// literals
public static Node objectlit(Node ... propdefs) {
Node objectlit = new Node(Token.OBJECTLIT);
for (Node propdef : propdefs) {
Preconditions.checkState(
propdef.isString() || propdef.isGetterDef() || propdef.isSetterDef());
Preconditions.checkState(
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Guard a, WarningsGuard b) {
int priorityDiff = a.getPriority() - b.getPriority();
if (priorityDiff != 0) {
return priorityDiff;
}
// If the warnings guards have the same priority, the one that
// was added last wins.
return orderOfAddition.get(b).intValue() -
orderOfAddition.get(a).intValue();
}
}
// The order that the guards are applied in.
private final TreeSet<WarningsGuard> guards =
new TreeSet<WarningsGuard>(guardComparator);
public ComposeWarningsGuard(List<WarningsGuard> guards) {
addGuards(guards);
}
public ComposeWarningsGuard(WarningsGuard... guards) {
this(Lists.newArrayList(guards));
}
void addGuard(WarningsGuard guard) {
if (guard instanceof ComposeWarningsGuard) {
// Reverse the guards, so that they have the same order in the result.
addGuards(((ComposeWarningsGuard) guard).guards.descendingSet());
} else {
numberOfAdds++;
orderOfAddition.put(guard, numberOfAdds);
guards.remove(guard);
guards.add(guard);
}
}
private void addGuards(Iterable<WarningsGuard> guards) {
for (WarningsGuard guard : guards) {
addGuard(guard);
}
}
@Override
public CheckLevel level(JSError error) {
for (WarningsGuard guard : guards) {
CheckLevel newLevel = guard.level(error);
if (newLevel != null) {
return newLevel;
}
}
return null;
}
@Override
public boolean disables(DiagnosticGroup group) {
nextSingleton:
for (DiagnosticType type : group.getTypes()) {
DiagnosticGroup singleton = DiagnosticGroup.forType(type);
for (WarningsGuard guard : guards) {
if (guard.disables(singleton)) {
continue nextSingleton;
} else if (guard.enables(singleton)) {
return false;
}
}
return false;
}
return true;
}
/**
* Determines whether this guard will "elevate" the status of any disabled
* diagnostic type in the group to a warning or an error.
*/
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>/*
* Copyright 2007 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.collect.Sets;
import com.google.javascript.jscomp.CheckLevel;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
/**
* <p>A basic error manager that sorts all errors and warnings reported to it to
* generate a sorted report when the {@link #generateReport()} method
* is called.</p>
*
* <p>This error manager does not produce any output, but subclasses can
* override the {@link #println(CheckLevel, JSError)} method to generate custom
* output.</p>
*
*/
public abstract class BasicErrorManager implements ErrorManager {
private final SortedSet<ErrorWithLevel> messages =
Sets.newTreeSet(new LeveledJSErrorComparator());
private int errorCount = 0;
private int warningCount = 0;
private double typedPercent = 0.0;
@Override
public void report(CheckLevel level, JSError error) {
if (messages.add(new ErrorWithLevel(error, level))) {
if (level == CheckLevel.ERROR) {
errorCount++;
} else if (level == CheckLevel.WARNING) {
warningCount++;
}
}
}
@Override
public void generateReport() {
for (ErrorWithLevel message : messages) {
println(message.level, message.error);
}
printSummary();
}
/**
* Print a message with a trailing new line. This method is called by the
*
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> {@link #generateReport()} method when generating messages.
*/
public abstract void println(CheckLevel level, JSError error);
/**
* Print the summary of the compilation - number of errors and warnings.
*/
protected abstract void printSummary();
@Override
public int getErrorCount() {
return errorCount;
}
@Override
public int getWarningCount() {
return warningCount;
}
@Override
public JSError[] getErrors() {
return toArray(CheckLevel.ERROR);
}
@Override
public JSError[] getWarnings() {
return toArray(CheckLevel.WARNING);
}
@Override
public void setTypedPercent(double typedPercent) {
this.typedPercent = typedPercent;
}
@Override
public double getTypedPercent() {
return typedPercent;
}
private JSError[] toArray(CheckLevel level) {
List<JSError> errors = new ArrayList<JSError>(messages.size());
for (ErrorWithLevel p : messages) {
if (p.level == level) {
errors.add(p.error);
}
}
return errors.toArray(new JSError[errors.size()]);
}
/**
* <p>Comparator of {@link JSError} with an associated {@link CheckLevel}.
* The ordering is the standard lexical ordering on the quintuple
* (file name, line number, {@link CheckLevel},
* character number, description).</p>
*
* <p>Note: this comparator imposes orderings that are inconsistent with
* {@link JSError#equals(Object)}.</p>
*/
static final class LeveledJSErrorComparator
implements Comparator<ErrorWithLevel> {
private static final int P1_LT_P2 = -1;
private static final int P1_GT_P2 = 1;
@Override
public int compare(ErrorWithLevel p1, ErrorWithLevel p2) {
// null is the smallest value
if (p2 == null) {
if (p1 == null) {
return 0;
} else {
return P1_GT_P2;
}
}
// check level
if (p1.level != p2.level) {
return p2.level.compareTo(p1.level
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>
private boolean frozen = false;
// The last slot defined in this flow instruction, and the head of the
// linked list of slots.
private LinkedFlowSlot lastSlot;
private LinkedFlowScope(FlatFlowScopeCache cache,
LinkedFlowScope directParent) {
this.cache = cache;
if (directParent == null) {
this.lastSlot = null;
this.depth = 0;
this.parent = cache.linkedEquivalent;
} else {
this.lastSlot = directParent.lastSlot;
this.depth = directParent.depth + 1;
this.parent = directParent;
}
}
LinkedFlowScope(FlatFlowScopeCache cache) {
this(cache, null);
}
LinkedFlowScope(LinkedFlowScope directParent) {
this(directParent.cache, directParent);
}
/** Gets the function scope for this flow scope. */
private Scope getFunctionScope() {
return cache.functionScope;
}
/** Whether this flows from a bottom scope. */
private boolean flowsFromBottom() {
return getFunctionScope().isBottom();
}
/**
* Creates an entry lattice for the flow.
*/
public static LinkedFlowScope createEntryLattice(Scope scope) {
return new LinkedFlowScope(new FlatFlowScopeCache(scope));
}
@Override
public void inferSlotType(String symbol, JSType type) {
Preconditions.checkState(!frozen);
lastSlot = new LinkedFlowSlot(symbol, type, lastSlot);
depth++;
cache.dirtySymbols.add(symbol);
}
@Override
public void inferQualifiedSlot(Node node, String symbol, JSType bottomType,
JSType inferredType) {
Scope functionScope = getFunctionScope();
if (functionScope.isLocal()) {
if (functionScope.getVar(symbol) == null && !functionScope.isBottom()) {
functionScope.declare(symbol, node, bottomType, null);
}
inferSlotType(symbol, inferredType);
}
}
@Override
public JSType getTypeOfThis() {
return cache.functionScope.getTypeOfThis();
}
@Override
public Node getRootNode() {
return getFunctionScope().getRootNode();
}
@Override
public StaticScope<JSType> getParentScope()
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> both 0 based.
int lineBaseOffset = 1;
if (generator instanceof SourceMapGeneratorV1
|| generator instanceof SourceMapGeneratorV2) {
lineBaseOffset = 0;
}
generator.addMapping(
sourceFile, originalName,
new FilePosition(node.getLineno() - lineBaseOffset, node.getCharno()),
outputStartPosition, outputEndPosition);
}
/**
* @param sourceFile The source file location to fixup.
* @return a remapped source file.
*/
private String fixupSourceLocation(String sourceFile) {
if (prefixMappings.isEmpty()) {
return sourceFile;
}
String fixed = sourceLocationFixupCache.get(sourceFile);
if (fixed != null) {
return fixed;
}
// Replace the first prefix found with its replacement
for (LocationMapping mapping : prefixMappings) {
if (sourceFile.startsWith(mapping.prefix)) {
fixed = mapping.replacement + sourceFile.substring(
mapping.prefix.length());
break;
}
}
// If none of the mappings match then use the original file path.
if (fixed == null) {
fixed = sourceFile;
}
sourceLocationFixupCache.put(sourceFile, fixed);
return fixed;
}
public void appendTo(Appendable out, String name) throws IOException {
generator.appendTo(out, name);
}
public void reset() {
generator.reset();
sourceLocationFixupCache.clear();
}
public void setStartingPosition(int offsetLine, int offsetIndex) {
generator.setStartingPosition(offsetLine, offsetIndex);
}
public void setWrapperPrefix(String prefix) {
generator.setWrapperPrefix(prefix);
}
public void validate(boolean validate) {
generator.validate(validate);
}
/**
* @param sourceMapLocationMappings
*/
public void setPrefixMappings(List<LocationMapping> sourceMapLocationMappings) {
this.prefixMappings = sourceMapLocationMappings;
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>
* Lists of modules at each depth. <code>modulesByDepth.get(3)</code> is a
* list of the modules at depth 3, for example.
*/
private List<List<JSModule>> modulesByDepth;
/**
* dependencyMap is a cache of dependencies that makes the dependsOn
* function faster. Each map entry associates a starting
* JSModule with the set of JSModules that are transitively dependent on the
* starting module.
*
* If the cache returns null, then the entry hasn't been filled in for that
* module.
*
* dependencyMap should be filled from leaf to root so that
* getTransitiveDepsDeepestFirst can use its results directly.
*/
private Map<JSModule, Set<JSModule>> dependencyMap = Maps.newHashMap();
/**
* Creates a module graph from a list of modules in dependency order.
*/
public JSModuleGraph(JSModule[] modulesInDepOrder) {
this(Lists.<JSModule>newArrayList(modulesInDepOrder));
}
/**
* Creates a module graph from a list of modules in dependency order.
*/
public JSModuleGraph(List<JSModule> modulesInDepOrder) {
modules = Sets.newHashSetWithExpectedSize(modulesInDepOrder.size());
modulesByDepth = Lists.newArrayList();
for (JSModule module : modulesInDepOrder) {
int depth = 0;
for (JSModule dep : module.getDependencies()) {
int depDepth = dep.getDepth();
if (depDepth < 0) {
throw new ModuleDependenceException(String.format(
"Modules not in dependency order: %s preceded %s",
module.getName(), dep.getName()),
module, dep);
}
depth = Math.max(depth, depDepth + 1);
}
module.setDepth(depth);
modules.add(module);
if (depth == modulesByDepth.size()) {
modulesByDepth.add(new ArrayList<JSModule>());
}
modulesByDepth.get(depth).add(module);
}
}
/**
* Gets an iterable over all modules.
*/
Iterable<JSModule> getAllModules() {
return modules;
}
/**
* Gets all the modules in dependency order. Modules
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> (dependsOn(m1, m) && dependsOn(m2, m)) {
return m;
}
}
}
return null;
}
/**
* Finds the deepest common dependency of two modules, including the
* modules themselves.
*
* @param m1 A module in this graph
* @param m2 A module in this graph
* @return The deepest common dep of {@code m1} and {@code m2}, or null if
* they have no common dependencies
*/
public JSModule getDeepestCommonDependencyInclusive(
JSModule m1, JSModule m2) {
if (m2 == m1 || dependsOn(m2, m1)) {
return m1;
} else if (dependsOn(m1, m2)) {
return m2;
}
return getDeepestCommonDependency(m1, m2);
}
/** Returns the deepest common dependency of the given modules. */
public JSModule getDeepestCommonDependencyInclusive(
Collection<JSModule> modules) {
Iterator<JSModule> iter = modules.iterator();
JSModule dep = iter.next();
while (iter.hasNext()) {
dep = getDeepestCommonDependencyInclusive(dep, iter.next());
}
return dep;
}
/**
* Creates an iterable over the transitive dependencies of module {@code m}
* in a non-increasing depth ordering. The result does not include the module
* {@code m}.
*
* @param m A module in this graph
* @return The transitive dependencies of module {@code m}
*/
Set<JSModule> getTransitiveDepsDeepestFirst(JSModule m) {
Set<JSModule> deps = dependencyMap.get(m);
if (deps != null) {
return deps;
}
deps = new TreeSet<JSModule>(new InverseDepthComparator());
addDeps(deps, m);
dependencyMap.put(m, deps);
return deps;
}
/**
* Adds a module's transitive dependencies to a set.
*/
private void addDeps(Set<JSModule> deps, JSModule m) {
for (JSModule dep : m.getDependencies()) {
deps.add(dep);
add
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Deps(deps, dep);
}
}
/**
* Replaces any files that are found multiple times with a single instance in
* the closest parent module that is common to all modules where it appears.
*
* JSCompiler normally errors if you attempt to compile modules containing the
* same file. This method can be used to remove duplicates before compiling
* to avoid such an error.
*/
public void coalesceDuplicateFiles() {
Multimap<String, JSModule> fileRefs = LinkedHashMultimap.create();
for (JSModule module : modules) {
for (CompilerInput jsFile : module.getInputs()) {
fileRefs.put(jsFile.getName(), module);
}
}
for (String path : fileRefs.keySet()) {
Collection<JSModule> refModules = fileRefs.get(path);
if (refModules.size() > 1) {
JSModule depModule = getDeepestCommonDependencyInclusive(refModules);
CompilerInput file = refModules.iterator().next().getByName(path);
for (JSModule module : refModules) {
if (module != depModule) {
module.removeByName(path);
}
}
if (!refModules.contains(depModule)) {
depModule.add(file);
}
}
}
}
/**
* Applies a DependencyOptions in "dependency sorting" and "dependency pruning"
* mode to the given list of inputs. Returns a new list with the files sorted
* and removed. This module graph will be updated to reflect the new list.
*
* If you need more fine-grained dependency management, you should create your
* own DependencyOptions and call
* {@code manageDependencies(DependencyOptions, List<CompilerInput>)}.
*
* @param entryPoints The entry points into the program.
* Expressed as JS symbols.
* @param inputs The original list of sources. Used to ensure that the sort
* is stable.
* @throws CircularDependencyException if there is a circular dependency
* between the provides and requires.
* @throws MissingProvideException if an entry point was not provided
* by any of the inputs.
* @see DependencyOptions for more info on how this works.
*/
public List<CompilerInput> manageDependencies(
List<String> entry
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Points,
List<CompilerInput> inputs)
throws CircularDependencyException, MissingProvideException {
DependencyOptions depOptions = new DependencyOptions();
depOptions.setDependencySorting(true);
depOptions.setDependencyPruning(true);
depOptions.setEntryPoints(entryPoints);
return manageDependencies(depOptions, inputs);
}
/**
* Apply the dependency options to the list of sources, returning a new
* source list re-ordering and dropping files as necessary.
* This module graph will be updated to reflect the new list.
*
* @param inputs The original list of sources. Used to ensure that the sort
* is stable.
* @throws CircularDependencyException if there is a circular dependency
* between the provides and requires.
* @throws MissingProvideException if an entry point was not provided
* by any of the inputs.
* @see DependencyOptions for more info on how this works.
*/
public List<CompilerInput> manageDependencies(
DependencyOptions depOptions,
List<CompilerInput> inputs)
throws CircularDependencyException, MissingProvideException {
SortedDependencies<CompilerInput> sorter =
new SortedDependencies<CompilerInput>(inputs);
Set<CompilerInput> entryPointInputs = Sets.newLinkedHashSet();
if (depOptions.shouldPruneDependencies()) {
if (!depOptions.shouldDropMoochers()) {
entryPointInputs.addAll(sorter.getInputsWithoutProvides());
}
for (String entryPoint : depOptions.getEntryPoints()) {
entryPointInputs.add(sorter.getInputProviding(entryPoint));
}
} else {
entryPointInputs.addAll(inputs);
}
// The order of inputs, sorted independently of modules.
List<CompilerInput> absoluteOrder =
sorter.getDependenciesOf(inputs, depOptions.shouldSortDependencies());
// Figure out which sources *must* be in each module.
ListMultimap<JSModule, CompilerInput> entryPointInputsPerModule =
LinkedListMultimap.create();
for (CompilerInput input : entryPointInputs) {
JSModule module = input.getModule();
Preconditions.checkNotNull(module);
entryPointInputsPerModule.put(module, input);
}
// Clear the modules of their inputs. This also nulls out
// the input's reference to its module.
for (JS
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Module module : getAllModules()) {
module.removeAll();
}
// Figure out which sources *must* be in each module, or in one
// of that module's dependencies.
for (JSModule module : entryPointInputsPerModule.keySet()) {
List<CompilerInput> transitiveClosure =
sorter.getDependenciesOf(
entryPointInputsPerModule.get(module),
depOptions.shouldSortDependencies());
for (CompilerInput input : transitiveClosure) {
JSModule oldModule = input.getModule();
if (oldModule == null) {
input.setModule(module);
} else {
input.setModule(null);
input.setModule(
getDeepestCommonDependencyInclusive(oldModule, module));
}
}
}
// All the inputs are pointing to the modules that own them. Yeah!
// Update the modules to reflect this.
for (CompilerInput input : absoluteOrder) {
JSModule module = input.getModule();
if (module != null) {
module.add(input);
}
}
// Now, generate the sorted result.
List<CompilerInput> result = Lists.newArrayList();
for (JSModule module : getAllModulesInDependencyOrder()) {
result.addAll(module.getInputs());
}
return result;
}
LinkedDirectedGraph<JSModule, String> toGraphvizGraph() {
LinkedDirectedGraph<JSModule, String> graphViz =
LinkedDirectedGraph.create();
for (JSModule module : getAllModulesInDependencyOrder()) {
graphViz.createNode(module);
for (JSModule dep : module.getDependencies()) {
graphViz.createNode(dep);
graphViz.connect(module, "->", dep);
}
}
return graphViz;
}
/**
* A module depth comparator that considers a deeper module to be
* "greater than" a shallower module. Uses module names to
* consistently break ties.
*/
private class DepthComparator implements Comparator<JSModule> {
@Override
public int compare(JSModule m1, JSModule m2) {
return depthCompare(m1, m2);
}
}
/**
* A module depth comparator that considers a deeper module to be "less than"
* a shallower module. Uses module names to
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> to prevent
* a variable from getting renamed, but no longer have any effect.
*/
private class NameRefInExternsCheck extends AbstractPostOrderCallback {
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.isName()) {
switch (parent.getType()) {
case Token.VAR:
case Token.FUNCTION:
case Token.PARAM_LIST:
// These are okay.
break;
case Token.GETPROP:
if (n == parent.getFirstChild()) {
Scope scope = t.getScope();
Scope.Var var = scope.getVar(n.getString());
if (var == null) {
t.report(n, UNDEFINED_EXTERN_VAR_ERROR, n.getString());
varsToDeclareInExterns.add(n.getString());
}
}
break;
default:
t.report(n, NAME_REFERENCE_IN_EXTERNS_ERROR, n.getString());
Scope scope = t.getScope();
Scope.Var var = scope.getVar(n.getString());
if (var == null) {
varsToDeclareInExterns.add(n.getString());
}
break;
}
}
}
}
/** Lazily create a "new" externs input for undeclared variables. */
private CompilerInput getSynthesizedExternsInput() {
return compiler.getSynthesizedExternsInput();
}
/** Lazily create a "new" externs root for undeclared variables. */
private Node getSynthesizedExternsRoot() {
if (synthesizedExternsRoot == null) {
CompilerInput synthesizedExterns = getSynthesizedExternsInput();
synthesizedExternsRoot = synthesizedExterns.getAstRoot(compiler);
}
return synthesizedExternsRoot;
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>
this.depth = -1;
}
/** Gets the module name. */
@Override
public String getName() {
return name;
}
@Override
public List<String> getProvides() {
return ImmutableList.<String>of(name);
}
@Override
public List<String> getRequires() {
ImmutableList.Builder<String> builder = ImmutableList.builder();
for (JSModule m : deps) {
builder.add(m.getName());
}
return builder.build();
}
@Override
public String getPathRelativeToClosureBase() {
throw new UnsupportedOperationException();
}
/** Adds a source file input to this module. */
public void add(JSSourceFile file) {
add(new CompilerInput(file));
}
/** Adds a source file input to this module. */
public void addFirst(JSSourceFile file) {
addFirst(new CompilerInput(file));
}
/** Adds a source code input to this module. */
public void add(CompilerInput input) {
inputs.add(input);
input.setModule(this);
}
/**
* Adds a source code input to this module. Call only if the input might
* already be associated with a module. Otherwise use
* add(CompilerInput input).
*/
void addAndOverrideModule(CompilerInput input) {
inputs.add(input);
input.overrideModule(this);
}
/** Adds a source code input to this module. */
public void addFirst(CompilerInput input) {
inputs.add(0, input);
input.setModule(this);
}
/** Adds a source code input to this module directly after other. */
public void addAfter(CompilerInput input, CompilerInput other) {
Preconditions.checkState(inputs.contains(other));
inputs.add(inputs.indexOf(other), input);
input.setModule(this);
}
/** Adds a dependency on another module. */
public void addDependency(JSModule dep) {
Preconditions.checkState(dep != this);
deps.add(dep);
}
/** Removes an input from this module. */
public void remove(CompilerInput input) {
input.setModule(null);
inputs.remove(input);
}
/** Removes all of the inputs from this module. */
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>
public void removeAll() {
for (CompilerInput input : inputs) {
input.setModule(null);
}
inputs.clear();
}
/**
* Gets the list of modules that this module depends on.
*
* @return A list that may be empty but not null
*/
public List<JSModule> getDependencies() {
return deps;
}
/**
* Gets the names of the modules that this module depends on,
* sorted alphabetically.
*/
List<String> getSortedDependencyNames() {
List<String> names = Lists.newArrayList();
for (JSModule module : getDependencies()) {
names.add(module.getName());
}
Collections.sort(names);
return names;
}
/**
* Returns the transitive closure of dependencies starting from the
* dependencies of this module.
*/
public Set<JSModule> getAllDependencies() {
Set<JSModule> allDeps = Sets.newHashSet(deps);
List<JSModule> workList = Lists.newArrayList(deps);
while (workList.size() > 0) {
JSModule module = workList.remove(workList.size() - 1);
for (JSModule dep : module.getDependencies()) {
if (allDeps.add(dep)) {
workList.add(dep);
}
}
}
return allDeps;
}
/** Returns this module and all of its dependencies in one list. */
public Set<JSModule> getThisAndAllDependencies() {
Set<JSModule> deps = getAllDependencies();
deps.add(this);
return deps;
}
/**
* Gets this module's list of source code inputs.
*
* @return A list that may be empty but not null
*/
public List<CompilerInput> getInputs() {
return inputs;
}
/** Returns the input with the given name or null if none. */
public CompilerInput getByName(String name) {
for (CompilerInput input : inputs) {
if (name.equals(input.getName())) {
return input;
}
}
return null;
}
/**
* Removes any input with the given name. Returns whether any were removed.
*/
public boolean removeByName(String name) {
boolean found = false;
Iterator<Compiler
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Input> iter = inputs.iterator();
while (iter.hasNext()) {
CompilerInput file = iter.next();
if (name.equals(file.getName())) {
iter.remove();
file.setModule(null);
found = true;
}
}
return found;
}
/** Returns the module name (primarily for debugging). */
@Override
public String toString() {
return name;
}
/**
* Removes any references to nodes of the AST. This method is needed to
* allow the ASTs to be garbage collected if the modules are kept around.
*/
public void clearAsts() {
for (CompilerInput input : inputs) {
input.clearAst();
}
}
/**
* Puts the JS files into a topologically sorted order by their dependencies.
*/
public void sortInputsByDeps(Compiler compiler) {
// Set the compiler, so that we can parse requires/provides and report
// errors properly.
for (CompilerInput input : inputs) {
input.setCompiler(compiler);
}
// Sort the JSModule in this order.
try {
List<CompilerInput> sortedList =
(new SortedDependencies<CompilerInput>(
Collections.<CompilerInput>unmodifiableList(inputs)))
.getSortedList();
inputs.clear();
inputs.addAll(sortedList);
} catch (CircularDependencyException e) {
compiler.report(
JSError.make(CIRCULAR_DEPENDENCY_ERROR, e.getMessage()));
}
}
/**
* Returns the given collection of modules in topological order.
*
* Note that this will return the modules in the same order if they are
* already sorted, and in general, will only change the order as necessary to
* satisfy the ordering dependencies. This can be important for cases where
* the modules do not properly specify all dependencies.
*/
public static JSModule[] sortJsModules(Collection<JSModule> modules)
throws CircularDependencyException {
// Sort the JSModule in this order.
List<JSModule> sortedList = (new SortedDependencies<JSModule>(
Lists.newArrayList(modules))).getSortedList();
return sortedList.toArray(new JSModule[sortedList.size()]);
}
/**
* @param dep the depth to set
*/
public void setDepth
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>return true if this node marks the start of a new basic block
*/
private static boolean isBlockBoundary(Node n, Node parent) {
if (parent != null) {
switch (parent.getType()) {
case Token.DO:
case Token.FOR:
case Token.TRY:
case Token.WHILE:
case Token.WITH:
// NOTE: TRY has up to 3 child blocks:
// TRY
// BLOCK
// BLOCK
// CATCH
// BLOCK
// Note that there is an explcit CATCH token but no explicit
// FINALLY token. For simplicity, we consider each BLOCK
// a separate basic BLOCK.
return true;
case Token.AND:
case Token.HOOK:
case Token.IF:
case Token.OR:
// The first child of a conditional is not a boundary,
// but all the rest of the children are.
return n != parent.getFirstChild();
}
}
return n.isCase();
}
private void addReference(NodeTraversal t, Var v, Reference reference) {
// Create collection if none already
ReferenceCollection referenceInfo = referenceMap.get(v);
if (referenceInfo == null) {
referenceInfo = new ReferenceCollection();
referenceMap.put(v, referenceInfo);
}
// Add this particular reference
referenceInfo.add(reference, t, v);
}
interface ReferenceMap {
ReferenceCollection getReferences(Var var);
}
private static class ReferenceMapWrapper implements ReferenceMap {
private final Map<Var, ReferenceCollection> referenceMap;
public ReferenceMapWrapper(Map<Var, ReferenceCollection> referenceMap) {
this.referenceMap = referenceMap;
}
@Override
public ReferenceCollection getReferences(Var var) {
return referenceMap.get(var);
}
}
/**
* Way for callers to add specific behavior during traversal that
* utilizes the built-up reference information.
*/
interface Behavior {
/**
* Called after we finish with a scope.
*/
void afterExitScope(NodeTraversal t, ReferenceMap referenceMap);
}
static Behavior DO_NOTHING_BEHAVIOR = new Behavior() {
@Override
public void afterExitScope(NodeTraversal t, ReferenceMap referenceMap) {}
};
/**
* A collection of
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> references. Can be subclassed to apply checks or
* store additional state when adding.
*/
static class ReferenceCollection implements Iterable<Reference> {
List<Reference> references = Lists.newArrayList();
@Override
public Iterator<Reference> iterator() {
return references.iterator();
}
void add(Reference reference, NodeTraversal t, Var v) {
references.add(reference);
}
/**
* Determines if the variable for this reference collection is
* "well-defined." A variable is well-defined if we can prove at
* compile-time that it's assigned a value before it's used.
*
* Notice that if this function returns false, this doesn't imply that the
* variable is used before it's assigned. It just means that we don't
* have enough information to make a definitive judgement.
*/
protected boolean isWellDefined() {
int size = references.size();
if (size == 0) {
return false;
}
// If this is a declaration that does not instantiate the variable,
// it's not well-defined.
Reference init = getInitializingReference();
if (init == null) {
return false;
}
Preconditions.checkState(references.get(0).isDeclaration());
BasicBlock initBlock = init.getBasicBlock();
for (int i = 1; i < size; i++) {
if (!initBlock.provablyExecutesBefore(
references.get(i).getBasicBlock())) {
return false;
}
}
return true;
}
/**
* Whether the variable is escaped into an inner scope.
*/
boolean isEscaped() {
Scope scope = null;
for (Reference ref : references) {
if (scope == null) {
scope = ref.scope;
} else if (scope != ref.scope) {
return true;
}
}
return false;
}
/**
* @param index The index into the references array to look for an
* assigning declaration.
*
* This is either the declaration if a value is assigned (such as
* "var a = 2", "function a()...", "... catch (a)...").
*/
private boolean isInitializingDeclarationAt(int index) {
Reference maybeInit = references.get(index);
if (maybeInit
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>();
if (baseConstructor != null &&
baseConstructor != getNativeType(OBJECT_FUNCTION_TYPE) &&
(baseConstructor.isInterface() && functionType.isConstructor())) {
compiler.report(
t.makeError(n, CONFLICTING_EXTENDED_TYPE, functionPrivateName));
} else {
// All interfaces are properly implemented by a class
for (JSType baseInterface : functionType.getImplementedInterfaces()) {
boolean badImplementedType = false;
ObjectType baseInterfaceObj = ObjectType.cast(baseInterface);
if (baseInterfaceObj != null) {
FunctionType interfaceConstructor =
baseInterfaceObj.getConstructor();
if (interfaceConstructor != null &&
!interfaceConstructor.isInterface()) {
badImplementedType = true;
}
} else {
badImplementedType = true;
}
if (badImplementedType) {
report(t, n, BAD_IMPLEMENTED_TYPE, functionPrivateName);
}
}
// check properties
validator.expectAllInterfaceProperties(t, n, functionType);
}
} else if (functionType.isInterface()) {
// Interface must extend only interfaces
for (ObjectType extInterface : functionType.getExtendedInterfaces()) {
if (extInterface.getConstructor() != null
&& !extInterface.getConstructor().isInterface()) {
compiler.report(
t.makeError(n, CONFLICTING_EXTENDED_TYPE, functionPrivateName));
}
}
// Interface cannot implement any interfaces
if (functionType.hasImplementedInterfaces()) {
compiler.report(t.makeError(n,
CONFLICTING_IMPLEMENTED_TYPE, functionPrivateName));
}
// Check whether the extended interfaces have any conflicts
if (functionType.getExtendedInterfacesCount() > 1) {
// Only check when extending more than one interfaces
HashMap<String, ObjectType> properties
= new HashMap<String, ObjectType>();
HashMap<String, ObjectType> currentProperties
= new HashMap<String, ObjectType>();
for (ObjectType interfaceType : functionType.getExtendedInterfaces()) {
currentProperties.clear();
checkInterfaceConflictProperties(t, n, functionPrivateName,
properties, currentProperties, interfaceType);
properties.putAll(currentProperties);
}
}
}
}
/**
* Visits a CALL node.
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> jsDocParser) {
if (jsDocParser.getFileOverviewJSDocInfo() != fileOverviewInfo) {
fileOverviewInfo = jsDocParser.getFileOverviewJSDocInfo();
return true;
}
return false;
}
private void handlePossibleFileOverviewJsDoc(Comment comment, Node irNode) {
JsDocInfoParser jsDocParser = createJsDocInfoParser(comment, irNode);
parsedComments.add(comment);
handlePossibleFileOverviewJsDoc(jsDocParser);
}
private JSDocInfo handleJsDoc(AstNode node, Node irNode) {
Comment comment = node.getJsDocNode();
if (comment != null) {
JsDocInfoParser jsDocParser = createJsDocInfoParser(comment, irNode);
parsedComments.add(comment);
if (!handlePossibleFileOverviewJsDoc(jsDocParser)) {
return jsDocParser.retrieveAndResetParsedJSDocInfo();
}
}
return null;
}
private Node transform(AstNode node) {
Node irNode = justTransform(node);
JSDocInfo jsDocInfo = handleJsDoc(node, irNode);
if (jsDocInfo != null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, node);
return irNode;
}
private Node transformNameAsString(Name node) {
Node irNode = transformDispatcher.processName(node, true);
JSDocInfo jsDocInfo = handleJsDoc(node, irNode);
if (jsDocInfo != null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, node);
return irNode;
}
private Node transformNumberAsString(NumberLiteral literalNode) {
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
JSDocInfo jsDocInfo = handleJsDoc(literalNode, irNode);
if (jsDocInfo != null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
// Return "1" instead of
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>child);
node.addChildToBack(c);
}
return node;
}
@Override
Node processAssignment(Assignment assignmentNode) {
Node assign = processInfixExpression(assignmentNode);
Node target = assign.getFirstChild();
if (!validAssignmentTarget(target)) {
errorReporter.error(
"invalid assignment target",
sourceName,
target.getLineno(), "", 0);
}
return assign;
}
@Override
Node processAstRoot(AstRoot rootNode) {
Node node = newNode(Token.SCRIPT);
for (com.google.javascript.rhino.head.Node child : rootNode) {
node.addChildToBack(transform((AstNode)child));
}
parseDirectives(node);
return node;
}
/**
* Parse the directives, encode them in the AST, and remove their nodes.
*
* For information on ES5 directives, see section 14.1 of
* Ecma-262, Edition 5.
*
* It would be nice if Rhino would eventually take care of this for
* us, but right now their directive-processing is a one-off.
*/
private void parseDirectives(Node node) {
// Remove all the directives, and encode them in the AST.
Set<String> directives = null;
while (isDirective(node.getFirstChild())) {
String directive = node.removeFirstChild().getFirstChild().getString();
if (directives == null) {
directives = Sets.newHashSet(directive);
} else {
directives.add(directive);
}
}
if (directives != null) {
node.setDirectives(directives);
}
}
private boolean isDirective(Node n) {
if (n == null) return false;
int nType = n.getType();
return nType == Token.EXPR_RESULT &&
n.getFirstChild().isString() &&
ALLOWED_DIRECTIVES.contains(n.getFirstChild().getString());
}
@Override
Node processBlock(Block blockNode) {
return processGeneric(blockNode);
}
@Override
Node processBreakStatement(BreakStatement statementNode) {
Node node = newNode(Token.BREAK);
if (statementNode.getBreakLabel() != null) {
Node labelName =
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> // A list of all the inputs that do not have provides.
private final List<INPUT> noProvides;
private final Map<String, INPUT> provideMap = Maps.newHashMap();
public SortedDependencies(List<INPUT> inputs)
throws CircularDependencyException {
this.inputs = Lists.newArrayList(inputs);
noProvides = Lists.newArrayList();
// Collect all symbols provided in these files.
for (INPUT input : inputs) {
Collection<String> currentProvides = input.getProvides();
if (currentProvides.isEmpty()) {
noProvides.add(input);
}
for (String provide : currentProvides) {
provideMap.put(provide, input);
}
}
// Get the direct dependencies.
final Multimap<INPUT, INPUT> deps = HashMultimap.create();
for (INPUT input : inputs) {
for (String req : input.getRequires()) {
INPUT dep = provideMap.get(req);
if (dep != null) {
deps.put(input, dep);
}
}
}
// Sort the inputs by sucking in 0-in-degree nodes until we're done.
sortedList = topologicalStableSort(inputs, deps);
// The dependency graph of inputs has a cycle iff sortedList is a proper
// subset of inputs. Also, it has a cycle iff the subgraph
// (inputs - sortedList) has a cycle. It's fairly easy to prove this
// by the lemma that a graph has a cycle iff it has a subgraph where
// no nodes have out-degree 0. I'll leave the proof of this as an exercise
// to the reader.
if (sortedList.size() < inputs.size()) {
List<INPUT> subGraph = Lists.newArrayList(inputs);
subGraph.removeAll(sortedList);
throw new CircularDependencyException(
cycleToString(findCycle(subGraph, deps)));
}
}
/**
* Return the input that gives us the given symbol.
* @throws MissingProvideException An exception if there is no
* input for this symbol.
*/
public INPUT getInputProviding(String symbol)
throws MissingProvideException {
if (provideMap.containsKey(symbol)) {
return provideMap.get(symbol);
}
throw new MissingProvideException(symbol);
}
/**
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>
* Returns the first circular dependency found. Expressed as a list of
* items in reverse dependency order (the second element depends on the
* first, etc.).
*/
private List<INPUT> findCycle(
List<INPUT> subGraph, Multimap<INPUT, INPUT> deps) {
return findCycle(subGraph.get(0), Sets.<INPUT>newHashSet(subGraph),
deps, Sets.<INPUT>newHashSet());
}
private List<INPUT> findCycle(
INPUT current, Set<INPUT> subGraph, Multimap<INPUT, INPUT> deps,
Set<INPUT> covered) {
if (covered.add(current)) {
List<INPUT> cycle = findCycle(
findRequireInSubGraphOrFail(current, subGraph),
subGraph, deps, covered);
// Don't add the input to the list if the cycle has closed already.
if (cycle.get(0) != cycle.get(cycle.size() - 1)) {
cycle.add(current);
}
return cycle;
} else {
// Explicitly use the add() method, to prevent a generics constructor
// warning that is dumb. The condition it's protecting is
// obscure, and I think people have proposed that it be removed.
List<INPUT> cycle = Lists.<INPUT>newArrayList();
cycle.add(current);
return cycle;
}
}
private INPUT findRequireInSubGraphOrFail(INPUT input, Set<INPUT> subGraph) {
for (String symbol : input.getRequires()) {
INPUT candidate = provideMap.get(symbol);
if (subGraph.contains(candidate)) {
return candidate;
}
}
throw new IllegalStateException("no require found in subgraph");
}
/**
* @param cycle A cycle in reverse-dependency order.
*/
private String cycleToString(List<INPUT> cycle) {
List<String> symbols = Lists.newArrayList();
for (int i = cycle.size() - 1; i >= 0; i--) {
symbols.add(cycle.get(i).getProvides().iterator().next());
}
symbols.add(symbols.get(0));
return Joiner.on(" -> ").join(symbols);
}
public List<INPUT> getSortedList() {
return Collections
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>.<INPUT>unmodifiableList(sortedList);
}
/**
* Gets all the dependencies of the given roots. The inputs must be returned
* in a stable order. In other words, if A comes before B, and A does not
* transitively depend on B, then A must also come before B in the returned
* list.
*/
public List<INPUT> getSortedDependenciesOf(List<INPUT> roots) {
return getDependenciesOf(roots, true);
}
/**
* Gets all the dependencies of the given roots. The inputs must be returned
* in a stable order. In other words, if A comes before B, and A does not
* transitively depend on B, then A must also come before B in the returned
* list.
*
* @param sorted If true, get them in topologically sorted order. If false,
* get them in the original order they were passed to the compiler.
*/
public List<INPUT> getDependenciesOf(List<INPUT> roots, boolean sorted) {
Preconditions.checkArgument(inputs.containsAll(roots));
Set<INPUT> included = Sets.newHashSet();
Deque<INPUT> worklist = new ArrayDeque<INPUT>(roots);
while (!worklist.isEmpty()) {
INPUT current = worklist.pop();
if (included.add(current)) {
for (String req : current.getRequires()) {
INPUT dep = provideMap.get(req);
if (dep != null) {
worklist.add(dep);
}
}
}
}
ImmutableList.Builder<INPUT> builder = ImmutableList.builder();
for (INPUT current : (sorted ? sortedList : inputs)) {
if (included.contains(current)) {
builder.add(current);
}
}
return builder.build();
}
public List<INPUT> getInputsWithoutProvides() {
return Collections.<INPUT>unmodifiableList(noProvides);
}
private static <T> List<T> topologicalStableSort(
List<T> items, Multimap<T, T> deps) {
if (items.size() == 0) {
// Priority queue blows up if we give it a size of 0. Since we need
// to special case this either way, just bail out.
return Lists.newArrayList();
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>
}
final Map<T, Integer> originalIndex = Maps.newHashMap();
for (int i = 0; i < items.size(); i++) {
originalIndex.put(items.get(i), i);
}
PriorityQueue<T> inDegreeZero = new PriorityQueue<T>(items.size(),
new Comparator<T>() {
@Override
public int compare(T a, T b) {
return originalIndex.get(a).intValue() -
originalIndex.get(b).intValue();
}
});
List<T> result = Lists.newArrayList();
Multiset<T> inDegree = HashMultiset.create();
Multimap<T, T> reverseDeps = ArrayListMultimap.create();
Multimaps.invertFrom(deps, reverseDeps);
// First, add all the inputs with in-degree 0.
for (T item : items) {
Collection<T> itemDeps = deps.get(item);
inDegree.add(item, itemDeps.size());
if (itemDeps.isEmpty()) {
inDegreeZero.add(item);
}
}
// Then, iterate to a fixed point over the reverse dependency graph.
while (!inDegreeZero.isEmpty()) {
T item = inDegreeZero.remove();
result.add(item);
for (T inWaiting : reverseDeps.get(item)) {
inDegree.remove(inWaiting, 1);
if (inDegree.count(inWaiting) == 0) {
inDegreeZero.add(inWaiting);
}
}
}
return result;
}
public static class CircularDependencyException extends Exception {
CircularDependencyException(String message) {
super(message);
}
}
public static class MissingProvideException extends Exception {
MissingProvideException(String provide) {
super(provide);
}
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> a named function: {0}.");
private final AbstractCompiler compiler;
private final CheckLevel checkLevel;
// NOTE(nicksantos): It's a lot faster to use a shared Set that
// we clear after each method call, because the Set never gets too big.
private final Set<BasicBlock> blocksWithDeclarations = Sets.newHashSet();
public VariableReferenceCheck(AbstractCompiler compiler,
CheckLevel checkLevel) {
this.compiler = compiler;
this.checkLevel = checkLevel;
}
@Override
public void process(Node externs, Node root) {
ReferenceCollectingCallback callback = new ReferenceCollectingCallback(
compiler, new ReferenceCheckingBehavior());
callback.process(externs, root);
}
@Override
public void hotSwapScript(Node scriptRoot, Node originalRoot) {
ReferenceCollectingCallback callback = new ReferenceCollectingCallback(
compiler, new ReferenceCheckingBehavior());
callback.hotSwapScript(scriptRoot, originalRoot);
}
/**
* Behavior that checks variables for redeclaration or early references
* just after they go out of scope.
*/
private class ReferenceCheckingBehavior implements Behavior {
@Override
public void afterExitScope(NodeTraversal t, ReferenceMap referenceMap) {
// TODO(bashir) In hot-swap version this means that for global scope we
// only go through all global variables accessed in the modified file not
// all global variables. This should be fixed.
// Check all vars after finishing a scope
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
checkVar(t, v, referenceMap.getReferences(v).references);
}
}
/**
* If the variable is declared more than once in a basic block, generate a
* warning. Also check if a variable is used in a given scope before it is
* declared, which suggest a likely error. Relies on the fact that
* references is in parse-tree order.
*/
private void checkVar(NodeTraversal t, Var v, List<Reference> references) {
blocksWithDeclarations.clear();
boolean isDeclaredInScope = false;
boolean isUnhoistedNamedFunction = false;
Reference hoistedFn = null;
// Look for hoisted functions.
for (Reference
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> reference : references) {
if (reference.isHoistedFunction()) {
blocksWithDeclarations.add(reference.getBasicBlock());
isDeclaredInScope = true;
hoistedFn = reference;
break;
} else if (NodeUtil.isFunctionDeclaration(
reference.getNode().getParent())) {
isUnhoistedNamedFunction = true;
}
}
for (Reference reference : references) {
if (reference == hoistedFn) {
continue;
}
BasicBlock basicBlock = reference.getBasicBlock();
boolean isDeclaration = reference.isDeclaration();
boolean allowDupe =
SyntacticScopeCreator.hasDuplicateDeclarationSuppression(
reference.getNode(), v);
if (isDeclaration && !allowDupe) {
// Look through all the declarations we've found so far, and
// check if any of them are before this block.
for (BasicBlock declaredBlock : blocksWithDeclarations) {
if (declaredBlock.provablyExecutesBefore(basicBlock)) {
// TODO(johnlenz): Fix AST generating clients that so they would
// have property StaticSourceFile attached at each node. Or
// better yet, make sure the generated code never violates
// the requirement to pass aggressive var check!
String filename = NodeUtil.getSourceName(reference.getNode());
compiler.report(
JSError.make(filename,
reference.getNode(),
checkLevel,
REDECLARED_VARIABLE, v.name));
break;
}
}
}
if (isUnhoistedNamedFunction && !isDeclaration && isDeclaredInScope) {
// Only allow an unhoisted named function to be used within the
// block it is declared.
for (BasicBlock declaredBlock : blocksWithDeclarations) {
if (!declaredBlock.provablyExecutesBefore(basicBlock)) {
String filename = NodeUtil.getSourceName(reference.getNode());
compiler.report(
JSError.make(filename,
reference.getNode(),
AMBIGUOUS_FUNCTION_DECL, v.name));
break;
}
}
}
if (!isDeclaration && !isDeclaredInScope) {
// Don't check the order of refer in externs files.
if (!reference.getNode().isFromExterns()) {
// Special case to deal with var goog = goog || {}
Node grandparent = reference
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>.getGrandparent();
if (grandparent.isName()
&& grandparent.getString() == v.name) {
continue;
}
// Only generate warnings if the scopes do not match in order
// to deal with possible forward declarations and recursion
if (reference.getScope() == v.scope) {
String filename = NodeUtil.getSourceName(reference.getNode());
compiler.report(
JSError.make(filename,
reference.getNode(),
checkLevel,
UNDECLARED_REFERENCE, v.name));
}
}
}
if (isDeclaration) {
blocksWithDeclarations.add(basicBlock);
isDeclaredInScope = true;
}
}
}
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>> slot = getSlot(property);
if (slot == null) {
return false;
}
return !slot.isTypeInferred();
}
@Override
void collectPropertyNames(Set<String> props) {
for (String prop : properties.keySet()) {
props.add(prop);
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
implicitPrototype.collectPropertyNames(props);
}
}
@Override
public boolean isPropertyTypeInferred(String property) {
StaticSlot<JSType> slot = getSlot(property);
if (slot == null) {
return false;
}
return slot.isTypeInferred();
}
@Override
public JSType getPropertyType(String property) {
StaticSlot<JSType> slot = getSlot(property);
if (slot == null) {
return getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return slot.getType();
}
@Override
public boolean isPropertyInExterns(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.isFromExterns();
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
return implicitPrototype.isPropertyInExterns(propertyName);
}
return false;
}
@Override
boolean defineProperty(String name, JSType type, boolean inferred,
Node propertyNode) {
if (hasOwnDeclaredProperty(name)) {
return false;
}
Property newProp = new Property(
name, type, inferred, propertyNode);
Property oldProp = properties.get(name);
if (oldProp != null) {
// This is to keep previously inferred jsdoc info, e.g., in a
// replaceScript scenario.
newProp.setJSDocInfo(oldProp.getJSDocInfo());
}
properties.put(name, newProp);
return true;
}
@Override
public boolean removeProperty(String name) {
return properties.remove(name) != null;
}
@Override
public Node getPropertyNode(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.getNode();
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>_THIS)) {
options.setWarningLevel(
DiagnosticGroups.GLOBAL_THIS,
options.checkGlobalThisLevel);
}
if (options.getLanguageIn() == LanguageMode.ECMASCRIPT5_STRICT) {
options.setWarningLevel(
DiagnosticGroups.ES5_STRICT,
CheckLevel.ERROR);
}
// Initialize the warnings guard.
List<WarningsGuard> guards = Lists.newArrayList();
guards.add(
new SuppressDocWarningsGuard(
getDiagnosticGroups().getRegisteredGroups()));
guards.add(options.getWarningsGuard());
ComposeWarningsGuard composedGuards = new ComposeWarningsGuard(guards);
// All passes must run the variable check. This synthesizes
// variables later so that the compiler doesn't crash. It also
// checks the externs file for validity. If you don't want to warn
// about missing variable declarations, we shut that specific
// error off.
if (!options.checkSymbols &&
!composedGuards.enables(DiagnosticGroups.CHECK_VARIABLES)) {
composedGuards.addGuard(new DiagnosticGroupWarningsGuard(
DiagnosticGroups.CHECK_VARIABLES, CheckLevel.OFF));
}
this.warningsGuard = composedGuards;
}
/**
* Initializes the instance state needed for a compile job.
*/
public void init(JSSourceFile[] externs, JSSourceFile[] inputs,
CompilerOptions options) {
init(Lists.<JSSourceFile>newArrayList(externs),
Lists.<JSSourceFile>newArrayList(inputs), options);
}
/**
* Initializes the instance state needed for a compile job.
*/
public void init(List<JSSourceFile> externs, List<JSSourceFile> inputs,
CompilerOptions options) {
JSModule module = new JSModule("[singleton]");
for (JSSourceFile input : inputs) {
module.add(input);
}
initModules(externs, Lists.newArrayList(module), options);
}
/**
* Initializes the instance state needed for a compile job if the sources
* are in modules.
*/
public void init(JSSourceFile[] externs, JSModule[] modules,
CompilerOptions options) {
initModules(Lists.<JSSourceFile>newArrayList(externs),
Lists
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>.<JSModule>newArrayList(modules), options);
}
/**
* Initializes the instance state needed for a compile job if the sources
* are in modules.
*/
public void initModules(
List<JSSourceFile> externs, List<JSModule> modules,
CompilerOptions options) {
initOptions(options);
checkFirstModule(modules);
fillEmptyModules(modules);
this.externs = makeCompilerInput(externs, true);
// Generate the module graph, and report any errors in the module
// specification as errors.
this.modules = modules;
if (modules.size() > 1) {
try {
this.moduleGraph = new JSModuleGraph(modules);
} catch (JSModuleGraph.ModuleDependenceException e) {
// problems with the module format. Report as an error. The
// message gives all details.
report(JSError.make(MODULE_DEPENDENCY_ERROR,
e.getModule().getName(), e.getDependentModule().getName()));
return;
}
} else {
this.moduleGraph = null;
}
this.inputs = getAllInputsFromModules(modules);
initBasedOnOptions();
initInputsByIdMap();
}
/**
* Do any initialization that is dependent on the compiler options.
*/
private void initBasedOnOptions() {
// Create the source map if necessary.
if (options.sourceMapOutputPath != null) {
sourceMap = options.sourceMapFormat.getInstance();
sourceMap.setPrefixMappings(options.sourceMapLocationMappings);
}
}
private List<CompilerInput> makeCompilerInput(
List<JSSourceFile> files, boolean isExtern) {
List<CompilerInput> inputs = Lists.newArrayList();
for (JSSourceFile file : files) {
inputs.add(new CompilerInput(file, isExtern));
}
return inputs;
}
private static final DiagnosticType EMPTY_MODULE_LIST_ERROR =
DiagnosticType.error("JSC_EMPTY_MODULE_LIST_ERROR",
"At least one module must be provided");
private static final DiagnosticType EMPTY_ROOT_MODULE_ERROR =
DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR",
"Root module '{0}' must contain at least one source code input
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>");
/**
* Verifies that at least one module has been provided and that the first one
* has at least one source code input.
*/
private void checkFirstModule(List<JSModule> modules) {
if (modules.isEmpty()) {
report(JSError.make(EMPTY_MODULE_LIST_ERROR));
} else if (modules.get(0).getInputs().isEmpty() && modules.size() > 1) {
// The root module may only be empty if there is exactly 1 module.
report(JSError.make(EMPTY_ROOT_MODULE_ERROR,
modules.get(0).getName()));
}
}
/**
* Fill any empty modules with a place holder file. It makes any cross module
* motion easier.
*/
private static void fillEmptyModules(List<JSModule> modules) {
for (JSModule module : modules) {
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
/**
* Rebuilds the internal list of inputs by iterating over all modules.
* This is necessary if inputs have been added to or removed from a module
* after the {@link #init(JSSourceFile[], JSModule[], CompilerOptions)} call.
*/
public void rebuildInputsFromModules() {
inputs = getAllInputsFromModules(modules);
initInputsByIdMap();
}
/**
* Builds a single list of all module inputs. Verifies that it contains no
* duplicates.
*/
private static List<CompilerInput> getAllInputsFromModules(
List<JSModule> modules) {
List<CompilerInput> inputs = Lists.newArrayList();
Map<String, JSModule> inputMap = Maps.newHashMap();
for (JSModule module : modules) {
for (CompilerInput input : module.getInputs()) {
String inputName = input.getName();
// NOTE(nicksantos): If an input is in more than one module,
// it will show up twice in the inputs list, and then we
// will get an error down the line.
inputs.add(input);
inputMap.put(inputName, module);
}
}
return inputs;
}
static final DiagnosticType DUPLICATE_INPUT =
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> = new SyntheticAst(name);
if (inputsById.containsKey(ast.getInputId())) {
throw new IllegalArgumentException("Conflicting externs name: " + name);
}
CompilerInput input = new CompilerInput(ast, true);
inputsById.put(input.getInputId(), input);
externsRoot.addChildToFront(ast.getAstRoot(this));
externs.add(0, input);
return input;
}
/** Add a source input dynamically. Intended for incremental compilation. */
void addIncrementalSourceAst(JsAst ast) {
InputId id = ast.getInputId();
Preconditions.checkState(getInput(id) == null, "Duplicate input %s", id.getIdName());
inputsById.put(id, new CompilerInput(ast));
}
/**
* Replace a source input dynamically. Intended for incremental
* re-compilation.
*
* If the new source input doesn't parse, then keep the old input
* in the AST and return false.
*
* @return Whether the new AST was attached successfully.
*/
boolean replaceIncrementalSourceAst(JsAst ast) {
CompilerInput oldInput = getInput(ast.getInputId());
Preconditions.checkNotNull(oldInput, "No input to replace: %s", ast.getInputId().getIdName());
Node newRoot = ast.getAstRoot(this);
if (newRoot == null) {
return false;
}
Node oldRoot = oldInput.getAstRoot(this);
if (oldRoot != null) {
oldRoot.getParent().replaceChild(oldRoot, newRoot);
} else {
getRoot().getLastChild().addChildToBack(newRoot);
}
CompilerInput newInput = new CompilerInput(ast);
inputsById.put(ast.getInputId(), newInput);
JSModule module = oldInput.getModule();
if (module != null) {
module.addAfter(newInput, oldInput);
module.remove(oldInput);
}
// Verify the input id is set properly.
Preconditions.checkState(
newInput.getInputId().equals(oldInput.getInputId()));
InputId inputIdOnAst = newInput.getAstRoot(this).getInputId();
Preconditions.checkState(newInput.getInputId().equals(inputIdOn
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Ast));
inputs.remove(oldInput);
return true;
}
/**
* Add a new source input dynamically. Intended for incremental compilation.
* <p>
* If the new source input doesn't parse, it will not be added, and a false
* will be returned.
*
* @param ast the JS Source to add.
* @return true if the source was added successfully, false otherwise.
* @throws IllegalStateException if an input for this ast already exists.
*/
boolean addNewSourceAst(JsAst ast) {
CompilerInput oldInput = getInput(ast.getInputId());
if (oldInput != null) {
throw new IllegalStateException(
"Input already exists: " + ast.getInputId().getIdName());
}
Node newRoot = ast.getAstRoot(this);
if (newRoot == null) {
return false;
}
getRoot().getLastChild().addChildToBack(newRoot);
CompilerInput newInput = new CompilerInput(ast);
// TODO(tylerg): handle this for multiple modules at some point.
if (moduleGraph == null && !modules.isEmpty()) {
// singleton module
modules.get(0).add(newInput);
}
inputsById.put(ast.getInputId(), newInput);
return true;
}
@Override
JSModuleGraph getModuleGraph() {
return moduleGraph;
}
@Override
public JSTypeRegistry getTypeRegistry() {
if (typeRegistry == null) {
typeRegistry = new JSTypeRegistry(oldErrorReporter, options.looseTypes);
}
return typeRegistry;
}
@Override
MemoizedScopeCreator getTypedScopeCreator() {
return getPassConfig().getTypedScopeCreator();
}
@SuppressWarnings("unchecked")
DefaultPassConfig ensureDefaultPassConfig() {
PassConfig passes = getPassConfig().getBasePassConfig();
Preconditions.checkState(passes instanceof DefaultPassConfig,
"PassConfigs must eventually delegate to the DefaultPassConfig");
return (DefaultPassConfig) passes;
}
public SymbolTable buildKnownSymbolTable() {
SymbolTable symbolTable = new SymbolTable(getTypeRegistry());
MemoizedScopeCreator typedScopeCreator = getTypedScopeCreator();
if (typedScopeCreator != null) {
symbolTable.addScopes(typedScopeCreator.getAll
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>
if (hasErrors()) {
return null;
}
}
}
// Check if inputs need to be rebuilt from modules.
boolean staleInputs = false;
for (CompilerInput input : inputs) {
Node n = input.getAstRoot(this);
// Inputs can have a null AST during initial parse.
if (n == null) {
continue;
}
if (n.getJSDocInfo() != null) {
JSDocInfo info = n.getJSDocInfo();
if (info.isExterns()) {
// If the input file is explicitly marked as an externs file, then
// assume the programmer made a mistake and throw it into
// the externs pile anyways.
externsRoot.addChildToBack(n);
input.setIsExtern(true);
input.getModule().remove(input);
externs.add(input);
staleInputs = true;
} else if (info.isNoCompile()) {
input.getModule().remove(input);
staleInputs = true;
}
}
}
if (staleInputs) {
fillEmptyModules(modules);
rebuildInputsFromModules();
}
// Build the AST.
for (CompilerInput input : inputs) {
Node n = input.getAstRoot(this);
if (n == null) {
continue;
}
if (devMode) {
runSanityCheck();
if (hasErrors()) {
return null;
}
}
if (options.sourceMapOutputPath != null ||
options.nameReferenceReportPath != null) {
// Annotate the nodes in the tree with information from the
// input file. This information is used to construct the SourceMap.
SourceInformationAnnotator sia =
new SourceInformationAnnotator(
input.getName(), options.devMode != DevMode.OFF);
NodeTraversal.traverse(this, n, sia);
}
jsRoot.addChildToBack(n);
}
if (hasErrors()) {
return null;
}
return externAndJsRoot;
} finally {
stopTracer(tracer, "parseInputs");
}
}
/**
* Transforms AMD and CJS modules to something closure compiler can
* process and creates JSModules and the corresponding dependency tree
* on the way
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>.
*/
private void processAMDAndCommonJSModules() {
Map<String, JSModule> modulesByName = Maps.newLinkedHashMap();
Map<CompilerInput, JSModule> modulesByInput = Maps.newLinkedHashMap();
// TODO(nicksantos): Refactor module dependency resolution to work nicely
// with multiple ways to express dependencies. Directly support JSModules
// that are equivalent to a signal file and which express their deps
// directly in the source.
for (CompilerInput input : inputs) {
input.setCompiler(this);
Node root = input.getAstRoot(this);
if (root == null) {
continue;
}
if (options.transformAMDToCJSModules) {
new TransformAMDToCJSModule(this).process(null, root);
}
if (options.processCommonJSModules) {
ProcessCommonJSModules cjs = new ProcessCommonJSModules(this,
options.commonJSModulePathPrefix);
cjs.process(null, root);
JSModule m = cjs.getModule();
if (m != null) {
modulesByName.put(m.getName(), m);
modulesByInput.put(input, m);
}
}
}
if (options.processCommonJSModules) {
List<JSModule> modules = Lists.newArrayList(modulesByName.values());
if (!modules.isEmpty()) {
this.modules = modules;
this.moduleGraph = new JSModuleGraph(this.modules);
}
for (JSModule module : modules) {
for (CompilerInput input : module.getInputs()) {
for (String require : input.getRequires()) {
module.addDependency(modulesByName.get(require));
}
}
}
try {
modules = Lists.newArrayList();
for (CompilerInput input : this.moduleGraph.manageDependencies(
options.dependencyOptions, inputs)) {
modules.add(modulesByInput.get(input));
}
this.modules = modules;
this.moduleGraph = new JSModuleGraph(modules);
} catch (Exception e) {
Throwables.propagate(e);
}
}
}
public Node parse(JSSourceFile file) {
initCompilerOptionsIfTesting();
addToDebugLog("Parsing: " + file.getName());
return new
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>
/** Name of the synthetic input that holds synthesized externs. */
static final String SYNTHETIC_EXTERNS = "{SyntheticVarsDeclar}";
private CompilerInput synthesizedExternsInput = null;
@Override
void addChangeHandler(CodeChangeHandler handler) {
codeChangeHandlers.add(handler);
}
@Override
void removeChangeHandler(CodeChangeHandler handler) {
codeChangeHandlers.remove(handler);
}
/**
* All passes should call reportCodeChange() when they alter
* the JS tree structure. This is verified by CompilerTestCase.
* This allows us to optimize to a fixed point.
*/
@Override
public void reportCodeChange() {
for (CodeChangeHandler handler : codeChangeHandlers) {
handler.reportChange();
}
}
@Override
public CodingConvention getCodingConvention() {
CodingConvention convention = options.getCodingConvention();
convention = convention != null ? convention : defaultCodingConvention;
return convention;
}
@Override
public boolean isIdeMode() {
return options.ideMode;
}
@Override
public boolean acceptEcmaScript5() {
switch (options.getLanguageIn()) {
case ECMASCRIPT5:
case ECMASCRIPT5_STRICT:
return true;
}
return false;
}
public LanguageMode languageMode() {
return options.getLanguageIn();
}
@Override
public boolean acceptConstKeyword() {
return options.acceptConstKeyword;
}
@Override
Config getParserConfig() {
if (parserConfig == null) {
Config.LanguageMode mode;
switch (options.getLanguageIn()) {
case ECMASCRIPT3:
mode = Config.LanguageMode.ECMASCRIPT3;
break;
case ECMASCRIPT5:
mode = Config.LanguageMode.ECMASCRIPT5;
break;
case ECMASCRIPT5_STRICT:
mode = Config.LanguageMode.ECMASCRIPT5_STRICT;
break;
default:
throw new IllegalStateException("unexpected language mode");
}
parserConfig = ParserRunner.createConfig(
isIdeMode(),
mode,
acceptConstKeyword(),
options.extraAnnotationNames);
}
return parserConfig;
}
@Override
public boolean isTypeChecking
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Name, int lineno, int charno) {
super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
Preconditions.checkNotNull(reference);
this.reference = reference;
this.sourceName = sourceName;
this.lineno = lineno;
this.charno = charno;
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, Node propertyNode) {
if (!isResolved()) {
// If this is an unresolved object type, we need to save all its
// properties and define them when it is resolved.
if (propertyContinuations == null) {
propertyContinuations = Lists.newArrayList();
}
propertyContinuations.add(
new PropertyContinuation(
propertyName, type, inferred, propertyNode));
return true;
} else {
return super.defineProperty(
propertyName, type, inferred, propertyNode);
}
}
private void finishPropertyContinuations() {
ObjectType referencedObjType = getReferencedObjTypeInternal();
if (referencedObjType != null && !referencedObjType.isUnknownType()) {
if (propertyContinuations != null) {
for (PropertyContinuation c : propertyContinuations) {
c.commit(this);
}
}
}
propertyContinuations = null;
}
/** Returns the type to which this refers (which is unknown if unresolved). */
public JSType getReferencedType() {
return getReferencedTypeInternal();
}
@Override
public String getReferenceName() {
return reference;
}
@Override
public String toString() {
return reference;
}
@Override
public boolean hasReferenceName() {
return true;
}
@Override
boolean isNamedType() {
return true;
}
@Override
public boolean isNominalType() {
return true;
}
/**
* Two named types are equivalent if they are the same {@code
* ObjectType} object. This is complicated by the fact that isEquivalent
* is sometimes called before we have a chance to resolve the type
* names.
*
* @return {@code true} iff {@code that} == {@code this} or {@code that}
* is a {@link NamedType} whose reference is the same as ours,
* or {@code that} is the type we reference.
*/
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> node, we want to grab the list
// of nodes that this node affects.
List<DiGraphNode<N, Branch>> nextNodes = isForward() ?
cfg.getDirectedSuccNodes(curNode) :
cfg.getDirectedPredNodes(curNode);
for (DiGraphNode<N, Branch> nextNode : nextNodes) {
if (nextNode != cfg.getImplicitReturn()) {
orderedWorkSet.add(nextNode);
}
}
}
step++;
}
if (isForward()) {
joinInputs(getCfg().getImplicitReturn());
}
}
/**
* Gets the state of the initial estimation at each node.
*
* @return Initial state.
*/
abstract L createInitialEstimateLattice();
/**
* Gets the incoming state of the entry node.
*
* @return Entry state.
*/
abstract L createEntryLattice();
/**
* Initializes the work list and the control flow graph.
*/
protected void initialize() {
// TODO(user): Calling clear doesn't deallocate the memory in a
// LinkedHashSet. Consider creating a new work set if we plan to repeatedly
// call analyze.
orderedWorkSet.clear();
for (DiGraphNode<N, Branch> node : cfg.getDirectedGraphNodes()) {
node.setAnnotation(new FlowState<L>(createInitialEstimateLattice(),
createInitialEstimateLattice()));
if (node != cfg.getImplicitReturn()) {
orderedWorkSet.add(node);
}
}
}
/**
* Performs a single flow through a node.
*
* @return {@code true} if the flow state differs from the previous state.
*/
protected boolean flow(DiGraphNode<N, Branch> node) {
FlowState<L> state = node.getAnnotation();
if (isForward()) {
L outBefore = state.out;
state.out = flowThrough(node.getValue(), state.in);
return !outBefore.equals(state.out);
} else {
L inBefore = state.in;
state.in = flowThrough(node.getValue(), state.out);
return !inBefore.equals(state.in);
}
}
/**
* Computes the new flow state at a given node's entry by
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> merging the
* output (input) lattice of the node's predecessor (successor).
*
* @param node Node to compute new join.
*/
protected void joinInputs(DiGraphNode<N, Branch> node) {
FlowState<L> state = node.getAnnotation();
if (isForward()) {
if (cfg.getEntry() == node) {
state.setIn(createEntryLattice());
} else {
List<DiGraphNode<N, Branch>> inNodes = cfg.getDirectedPredNodes(node);
if (inNodes.size() == 1) {
FlowState<L> inNodeState = inNodes.get(0).getAnnotation();
state.setIn(inNodeState.getOut());
} else if (inNodes.size() > 1) {
List<L> values = new ArrayList<L>(inNodes.size());
for (DiGraphNode<N, Branch> currentNode : inNodes) {
FlowState<L> currentNodeState = currentNode.getAnnotation();
values.add(currentNodeState.getOut());
}
state.setIn(joinOp.apply(values));
}
}
} else {
List<DiGraphNode<N, Branch>> inNodes = cfg.getDirectedSuccNodes(node);
if (inNodes.size() == 1) {
DiGraphNode<N, Branch> inNode = inNodes.get(0);
if (inNode == cfg.getImplicitReturn()) {
state.setOut(createEntryLattice());
} else {
FlowState<L> inNodeState = inNode.getAnnotation();
state.setOut(inNodeState.getIn());
}
} else if (inNodes.size() > 1) {
List<L> values = new ArrayList<L>(inNodes.size());
for (DiGraphNode<N, Branch> currentNode : inNodes) {
FlowState<L> currentNodeState = currentNode.getAnnotation();
values.add(currentNodeState.getIn());
}
state.setOut(joinOp.apply(values));
}
}
}
/**
* The in and out states of a node.
*
* @param <L> Input and output lattice element type.
*/
static class FlowState<L extends Lattice
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Element> implements Annotation {
private L in;
private L out;
/**
* Private constructor. No other classes should create new states.
*
* @param inState Input.
* @param outState Output.
*/
private FlowState(L inState, L outState) {
Preconditions.checkNotNull(inState);
Preconditions.checkNotNull(outState);
this.in = inState;
this.out = outState;
}
L getIn() {
return in;
}
void setIn(L in) {
Preconditions.checkNotNull(in);
this.in = in;
}
L getOut() {
return out;
}
void setOut(L out) {
Preconditions.checkNotNull(out);
this.out = out;
}
@Override
public String toString() {
return String.format("IN: %s OUT: %s", in, out);
}
@Override
public int hashCode() {
return Objects.hashCode(in, out);
}
}
/**
* The exception to be thrown if the analysis has been running for a long
* number of iterations. Chances are the analysis is not monotonic, a
* fixed-point cannot be found and it is currently stuck in an infinite loop.
*/
static class MaxIterationsExceededException extends RuntimeException {
private static final long serialVersionUID = 1L;
MaxIterationsExceededException(String msg) {
super(msg);
}
}
abstract static class BranchedForwardDataFlowAnalysis
<N, L extends LatticeElement> extends DataFlowAnalysis<N, L> {
@Override
protected void initialize() {
orderedWorkSet.clear();
for (DiGraphNode<N, Branch> node : getCfg().getDirectedGraphNodes()) {
int outEdgeCount = getCfg().getOutEdges(node.getValue()).size();
List<L> outLattices = Lists.newArrayList();
for (int i = 0; i < outEdgeCount; i++) {
outLattices.add(createInitialEstimateLattice());
}
node.setAnnotation(new BranchedFlowState<L>(
createInitialEstimateLattice(), outLattices));
if (node != getCfg().getImplicitReturn()) {
orderedWorkSet.add(node);
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>FlowState<L> predNodeState = predNode.getAnnotation();
L in = predNodeState.out.get(
getCfg().getDirectedSuccNodes(predNode).indexOf(node));
values.add(in);
}
if (getCfg().getEntry() == node) {
state.setIn(createEntryLattice());
} else if (!values.isEmpty()) {
state.setIn(joinOp.apply(values));
}
}
}
/**
* The in and out states of a node.
*
* @param <L> Input and output lattice element type.
*/
static class BranchedFlowState<L extends LatticeElement>
implements Annotation {
private L in;
private List<L> out;
/**
* Private constructor. No other classes should create new states.
*
* @param inState Input.
* @param outState Output.
*/
private BranchedFlowState(L inState, List<L> outState) {
Preconditions.checkNotNull(inState);
Preconditions.checkNotNull(outState);
this.in = inState;
this.out = outState;
}
L getIn() {
return in;
}
void setIn(L in) {
Preconditions.checkNotNull(in);
this.in = in;
}
List<L> getOut() {
return out;
}
void setOut(List<L> out) {
Preconditions.checkNotNull(out);
for (L item : out) {
Preconditions.checkNotNull(item);
}
this.out = out;
}
@Override
public String toString() {
return String.format("IN: %s OUT: %s", in, out);
}
@Override
public int hashCode() {
return Objects.hashCode(in, out);
}
}
/**
* Compute set of escaped variables. When a variable is escaped in a
* dataflow analysis, it can be reference outside of the code that we are
* analyzing. A variable is escaped if any of the following is true:
*
* <p><ol>
* <li>It is defined as the exception name in CATCH clause so it became a
* variable local not to our definition of scope.</li>
* <li>Exported variables as they
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> can be needed after the script terminates.
* </li>
* <li>Names of named functions because in javascript, <i>function foo(){}</i>
* does not kill <i>foo</i> in the dataflow.</li>
*/
static void computeEscaped(final Scope jsScope, final Set<Var> escaped,
AbstractCompiler compiler) {
// TODO(user): Very good place to store this information somewhere.
AbstractPostOrderCallback finder = new AbstractPostOrderCallback() {
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (jsScope == t.getScope() || !n.isName()
|| parent.isFunction()) {
return;
}
String name = n.getString();
Var var = t.getScope().getVar(name);
if (var != null && var.scope == jsScope) {
escaped.add(jsScope.getVar(name));
}
}
};
NodeTraversal t = new NodeTraversal(compiler, finder);
t.traverseAtScope(jsScope);
// 1: Remove the exception name in CATCH which technically isn't local to
// begin with.
for (Iterator<Var> i = jsScope.getVars(); i.hasNext();) {
Var var = i.next();
if (var.getParentNode().isCatch() ||
compiler.getCodingConvention().isExported(var.getName())) {
escaped.add(var);
}
}
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS><String> getters = Sets.newHashSet();
Set<String> setters = Sets.newHashSet();
for (Node key = n.getFirstChild();
key != null;
key = key.getNext()) {
if (!noCajaChecks && key.getString().endsWith("__")) {
t.report(key, ILLEGAL_NAME);
}
if (!key.isSetterDef()) {
// normal property and getter cases
if (getters.contains(key.getString())) {
t.report(key, DUPLICATE_OBJECT_KEY);
} else {
getters.add(key.getString());
}
}
if (!key.isGetterDef()) {
// normal property and setter cases
if (setters.contains(key.getString())) {
t.report(key, DUPLICATE_OBJECT_KEY);
} else {
setters.add(key.getString());
}
}
}
}
/** Checks that label names are valid. */
private void checkLabel(NodeTraversal t, Node n) {
if (n.getFirstChild().getString().endsWith("__")) {
if (!noCajaChecks) {
t.report(n.getFirstChild(), ILLEGAL_NAME);
}
}
}
/** Checks that are performed on non-extern code only. */
private class NonExternChecks extends AbstractPostOrderCallback {
@Override public void visit(NodeTraversal t, Node n, Node parent) {
if ((n.isName()) && isDeclaration(n)) {
checkDeclaration(t, n);
} else if (n.isGetProp()) {
checkProperty(t, n);
}
}
/** Checks for illegal declarations. */
private void checkDeclaration(NodeTraversal t, Node n) {
if ("eval".equals(n.getString())) {
t.report(n, EVAL_DECLARATION);
} else if ("arguments".equals(n.getString())) {
t.report(n, ARGUMENTS_DECLARATION);
} else if (n.getString().endsWith("__")) {
if (!noCajaChecks) {
t.report(n, ILLEGAL_NAME);
}
}
}
/** Checks for illegal property accesses. */
private void checkProperty(NodeTraversal t, Node n
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Set;
/**
* An enum type representing a branded collection of elements. Each element
* is referenced by its name, and has an {@link EnumElementType} type.
*/
public class EnumType extends PrototypeObjectType {
private static final long serialVersionUID = 1L;
/**
* The object literal or alias which this type represents.
* It may be {@code null}.
*/
private final Node source;
// the type of the individual elements
private EnumElementType elementsType;
// the elements' names (they all have the same type)
private final Set<String> elements = new HashSet<String>();
/**
* Creates an enum type.
*
* @param name the enum's name
* @param elementsType the base type of the individual elements
*/
EnumType(JSTypeRegistry registry, String name, Node source,
JSType elementsType) {
super(registry, "enum{" + name + "}", null);
this.source = source;
this.elementsType = new EnumElementType(registry, elementsType, name);
}
/**
* Gets the source node or null if this is an unknown enum.
*/
public Node getSource() {
return source;
}
@Override
public EnumType toMaybeEnumType() {
return this;
}
@Override
public ObjectType getImplicitPrototype() {
return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE);
}
/**
* Gets the elements defined on this enum.
* @return the elements' names defined on this enum. The returned set is
* immutable.
*/
public Set<String> getElements() {
return Collections.unmodifiableSet(elements);
}
/**
* Defines a new element on this enum.
* @param name the name of the new element
* @param definingNode the {@code Node} that defines this new element
* @return true iff the new element is added successfully
*/
public boolean defineElement(String name, Node definingNode) {
elements.add(name);
return defineDeclaredProperty(name, elementsType, definingNode);
}
/**
* Gets the elements' type.
*/
public EnumElementType getElementsType() {
return elementsType;
}
@Override
public TernaryValue testForEquality(JSType that) {
TernaryValue result
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> name <arg2>
* -- block
* |
* --return
* |
* --add
* |-- string foo
* -- name <arg1>
* </pre>
*
* @param builder the message builder
* @param node the function node that contains a message
* @throws MalformedException if the parsed message is invalid
*/
private void extractFromFunctionNode(Builder builder, Node node)
throws MalformedException {
Set<String> phNames = Sets.newHashSet();
for (Node fnChild : node.children()) {
switch (fnChild.getType()) {
case Token.NAME:
// This is okay. The function has a name, but it is empty.
break;
case Token.PARAM_LIST:
// Parse the placeholder names from the function argument list.
for (Node argumentNode : fnChild.children()) {
if (argumentNode.isName()) {
String phName = argumentNode.getString();
if (phNames.contains(phName)) {
throw new MalformedException("Duplicate placeholder name: "
+ phName, argumentNode);
} else {
phNames.add(phName);
}
}
}
break;
case Token.BLOCK:
// Build the message's value by examining the return statement
Node returnNode = fnChild.getFirstChild();
if (!returnNode.isReturn()) {
throw new MalformedException("RETURN node expected; found: "
+ getReadableTokenName(returnNode), returnNode);
}
for (Node child : returnNode.children()) {
extractFromReturnDescendant(builder, child);
}
// Check that all placeholders from the message text have appropriate
// object literal keys
for (String phName : builder.getPlaceholders()) {
if(!phNames.contains(phName)) {
throw new MalformedException(
"Unrecognized message placeholder referenced: " + phName,
returnNode);
}
}
break;
default:
throw new MalformedException(
"NAME, LP, or BLOCK node expected; found: "
+ getReadableTokenName(node), fnChild);
}
}
}
/**
* Appends value parts to the message builder by traversing the descendants
* of the given RETURN node.
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>();
if (stringLiteralNode == null) {
throw new MalformedException("Message string literal expected",
stringLiteralNode);
}
// Parse the message string and append parts to the builder
parseMessageTextNode(builder, stringLiteralNode);
Node objLitNode = stringLiteralNode.getNext();
Set<String> phNames = Sets.newHashSet();
if (objLitNode != null) {
// Register the placeholder names
if (!objLitNode.isObjectLit()) {
throw new MalformedException("OBJLIT node expected", objLitNode);
}
for (Node aNode = objLitNode.getFirstChild(); aNode != null;
aNode = aNode.getNext()) {
if (!aNode.isString()) {
throw new MalformedException("STRING node expected as OBJLIT key",
aNode);
}
String phName = aNode.getString();
if (!isLowerCamelCaseWithNumericSuffixes(phName)) {
throw new MalformedException(
"Placeholder name not in lowerCamelCase: " + phName, aNode);
}
if (phNames.contains(phName)) {
throw new MalformedException("Duplicate placeholder name: "
+ phName, aNode);
}
phNames.add(phName);
}
}
// Check that all placeholders from the message text have appropriate objlit
// values
Set<String> usedPlaceholders = builder.getPlaceholders();
for (String phName : usedPlaceholders) {
if(!phNames.contains(phName)) {
throw new MalformedException(
"Unrecognized message placeholder referenced: " + phName,
objLitNode);
}
}
// Check that objLiteral have only names that are present in the
// message text
for (String phName : phNames) {
if(!usedPlaceholders.contains(phName)) {
throw new MalformedException(
"Unused message placeholder: " + phName,
objLitNode);
}
}
}
/**
* Appends the message parts in a JS message value extracted from the given
* text node.
*
* @param builder the js message builder to append parts to
* @param node the node with string literal that contains the message text
* @throws MalformedException if {@code value} contains a reference to
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>; if any of these
* properties is invalidated it causes an error.
*/
private final Map<String, CheckLevel> propertiesToErrorFor;
private class Property {
/** The name of the property. */
final String name;
/** All types on which the field exists, grouped together if related. */
private UnionFind<T> types;
/**
* A set of types for which renaming this field should be skipped. This
* list is first filled by fields defined in the externs file.
*/
Set<T> typesToSkip = Sets.newHashSet();
/**
* If true, do not rename any instance of this field, as it has been
* referenced from an unknown type.
*/
boolean skipRenaming;
/** Set of nodes for this field that need renaming. */
Set<Node> renameNodes = Sets.newHashSet();
/**
* Map from node to the highest type in the prototype chain containing the
* field for that node. In the case of a union, the type is the highest type
* of one of the types in the union.
*/
final Map<Node, T> rootTypes = Maps.newHashMap();
Property(String name) {
this.name = name;
}
/** Returns the types on which this field is referenced. */
UnionFind<T> getTypes() {
if (types == null) {
types = new StandardUnionFind<T>();
}
return types;
}
/**
* Record that this property is referenced from this type.
* @return true if the type was recorded for this property, else false,
* which would happen if the type was invalidating.
*/
boolean addType(T type, T top, T relatedType) {
checkState(!skipRenaming, "Attempt to record skipped property: %s", name);
if (typeSystem.isInvalidatingType(top)) {
invalidate();
return false;
} else {
if (typeSystem.isTypeToSkip(top)) {
addTypeToSkip(top);
}
if (relatedType == null) {
getTypes().add(top);
} else {
getTypes().union(top, relatedType);
}
typeSystem.recordInterfaces(type, top, this);
return true;
}
}
/** Records the
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> given type as one to skip for this property. */
void addTypeToSkip(T type) {
for (T skipType : typeSystem.getTypesToSkipForType(type)) {
typesToSkip.add(skipType);
getTypes().union(skipType, type);
}
}
/** Invalidates any types related to invalid types. */
void expandTypesToSkip() {
// If we are not going to rename any properties, then we do not need to
// update the list of invalid types, as they are all invalid.
if (shouldRename()) {
int count = 0;
while (true) {
// It should usually only take one time through this do-while.
checkState(++count < 10, "Stuck in loop expanding types to skip.");
// Make sure that the representative type for each type to skip is
// marked as being skipped.
Set<T> rootTypesToSkip = Sets.newHashSet();
for (T subType : typesToSkip) {
rootTypesToSkip.add(types.find(subType));
}
typesToSkip.addAll(rootTypesToSkip);
Set<T> newTypesToSkip = Sets.newHashSet();
Set<T> allTypes = types.elements();
int originalTypesSize = allTypes.size();
for (T subType : allTypes) {
if (!typesToSkip.contains(subType)
&& typesToSkip.contains(types.find(subType))) {
newTypesToSkip.add(subType);
}
}
for (T newType : newTypesToSkip) {
addTypeToSkip(newType);
}
// If there were not any new types added, we are done here.
if (types.elements().size() == originalTypesSize) {
break;
}
}
}
}
/** Returns true if any instance of this property should be renamed. */
boolean shouldRename() {
return !skipRenaming && types != null
&& types.allEquivalenceClasses().size() > 1;
}
/**
* Returns true if this property should be renamed on this type.
* expandTypesToSkip() should be called before this, if anything has been
* added to the typesToSkip list.
*/
boolean shouldRename(
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>T type) {
return !skipRenaming && !typesToSkip.contains(type);
}
/**
* Invalidates a field from renaming. Used for field references on an
* object with unknown type.
*/
boolean invalidate() {
boolean changed = !skipRenaming;
skipRenaming = true;
types = null;
return changed;
}
/**
* Schedule the node to potentially be renamed.
* @param node the node to rename
* @param type the highest type in the prototype chain for which the
* property is defined
* @return True if type was accepted without invalidation or if the property
* was already invalidated. False if this property was invalidated this
* time.
*/
boolean scheduleRenaming(Node node, T type) {
if (!skipRenaming) {
if (typeSystem.isInvalidatingType(type)) {
invalidate();
return false;
}
renameNodes.add(node);
rootTypes.put(node, type);
}
return true;
}
}
private Map<String, Property> properties = Maps.newHashMap();
static DisambiguateProperties<JSType> forJSTypeSystem(
AbstractCompiler compiler,
Map<String, CheckLevel> propertiesToErrorFor) {
return new DisambiguateProperties<JSType>(
compiler, new JSTypeSystem(compiler), propertiesToErrorFor);
}
static DisambiguateProperties<ConcreteType> forConcreteTypeSystem(
AbstractCompiler compiler, TightenTypes tt,
Map<String, CheckLevel> propertiesToErrorFor) {
return new DisambiguateProperties<ConcreteType>(
compiler, new ConcreteTypeSystem(tt, compiler.getCodingConvention()),
propertiesToErrorFor);
}
/**
* This constructor should only be called by one of the helper functions
* above for either the JSType system, or the concrete type system.
*/
private DisambiguateProperties(AbstractCompiler compiler,
TypeSystem<T> typeSystem, Map<String, CheckLevel> propertiesToErrorFor) {
this.compiler = compiler;
this.typeSystem = typeSystem;
this.propertiesToErrorFor = propertiesToErrorFor;
if (!this.propertiesToErrorFor.isEmpty()) {
this.invalidationMap =
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>. */
T getTypeWithProperty(String field, T type) {
return typeSystem.getTypeWithProperty(field, type);
}
/** Tracks the current type system scope while traversing. */
private abstract class AbstractScopingCallback implements ScopedCallback {
protected final Stack<StaticScope<T>> scopes =
new Stack<StaticScope<T>>();
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
scopes.push(typeSystem.getRootScope());
} else {
scopes.push(typeSystem.getFunctionScope(t.getScopeRoot()));
}
}
@Override
public void exitScope(NodeTraversal t) {
scopes.pop();
}
/** Returns the current scope at this point in the file. */
protected StaticScope<T> getScope() {
return scopes.peek();
}
}
/**
* Finds all properties defined in the externs file and sets them as
* ineligible for renaming from the type on which they are defined.
*/
private class FindExternProperties extends AbstractScopingCallback {
@Override public void visit(NodeTraversal t, Node n, Node parent) {
// TODO(johnlenz): Support object-literal property definitions.
if (n.isGetProp()) {
String field = n.getLastChild().getString();
T type = typeSystem.getType(getScope(), n.getFirstChild(), field);
Property prop = getProperty(field);
if (typeSystem.isInvalidatingType(type)) {
prop.invalidate();
} else {
prop.addTypeToSkip(type);
// If this is a prototype property, then we want to skip assignments
// to the instance type as well. These assignments are not usually
// seen in the extern code itself, so we must handle them here.
if ((type = typeSystem.getInstanceFromPrototype(type)) != null) {
prop.getTypes().add(type);
prop.typesToSkip.add(type);
}
}
}
}
}
/**
* Traverses the tree, building a map from field names to Nodes for all
* fields that can be renamed.
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>.newHashSet(
registry.getNativeType(JSTypeNative.ALL_TYPE),
registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE),
registry.getNativeType(JSTypeNative.NO_TYPE),
registry.getNativeType(JSTypeNative.FUNCTION_PROTOTYPE),
registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE),
registry.getNativeType(JSTypeNative.OBJECT_PROTOTYPE),
registry.getNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE),
registry.getNativeType(JSTypeNative.UNKNOWN_TYPE));
}
@Override public void addInvalidatingType(JSType type) {
checkState(!type.isUnionType());
invalidatingTypes.add(type);
}
@Override public StaticScope<JSType> getRootScope() { return null; }
@Override public StaticScope<JSType> getFunctionScope(Node node) {
return null;
}
@Override public JSType getType(
StaticScope<JSType> scope, Node node, String prop) {
if (node.getJSType() == null) {
return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return node.getJSType();
}
@Override public boolean isInvalidatingType(JSType type) {
if (type == null || invalidatingTypes.contains(type) ||
type.isUnknownType() /* unresolved types */) {
return true;
}
ObjectType objType = ObjectType.cast(type);
return objType != null && !objType.hasReferenceName();
}
@Override public ImmutableSet<JSType> getTypesToSkipForType(JSType type) {
type = type.restrictByNotNullOrUndefined();
if (type.isUnionType()) {
Set<JSType> types = Sets.newHashSet(type);
for (JSType alt : type.toMaybeUnionType().getAlternates()) {
types.addAll(getTypesToSkipForTypeNonUnion(type));
}
return ImmutableSet.copyOf(types);
} else if (type.isEnumElementType()) {
return getTypesToSkipForType(
type.toMaybeEnumElementType().getPrimitiveType());
}
return ImmutableSet.copyOf(getTypesToSkipForTypeNon
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Union(type));
}
private Set<JSType> getTypesToSkipForTypeNonUnion(JSType type) {
Set<JSType> types = Sets.newHashSet();
JSType skipType = type;
while (skipType != null) {
types.add(skipType);
ObjectType objSkipType = skipType.toObjectType();
if (objSkipType != null) {
skipType = objSkipType.getImplicitPrototype();
} else {
break;
}
}
return types;
}
@Override public boolean isTypeToSkip(JSType type) {
return type.isEnumType() || (type.autoboxesTo() != null);
}
@Override public JSType restrictByNotNullOrUndefined(JSType type) {
return type.restrictByNotNullOrUndefined();
}
@Override public Iterable<JSType> getTypeAlternatives(JSType type) {
if (type.isUnionType()) {
return type.toMaybeUnionType().getAlternates();
} else {
ObjectType objType = type.toObjectType();
if (objType != null &&
objType.getConstructor() != null &&
objType.getConstructor().isInterface()) {
List<JSType> list = Lists.newArrayList();
for (FunctionType impl
: registry.getDirectImplementors(objType)) {
list.add(impl.getInstanceType());
}
return list;
} else {
return null;
}
}
}
@Override public ObjectType getTypeWithProperty(String field, JSType type) {
if (type == null) {
return null;
}
if (type.isEnumElementType()) {
return getTypeWithProperty(
field, type.toMaybeEnumElementType().getPrimitiveType());
}
if (!(type instanceof ObjectType)) {
if (type.autoboxesTo() != null) {
type = type.autoboxesTo();
} else {
return null;
}
}
// Ignore the prototype itself at all times.
if ("prototype".equals(field)) {
return null;
}
// We look up the prototype chain to find the highest place (if any) that
// this appears. This will make references to overriden properties look
// like references to the initial property, so they are renamed alike.
ObjectType foundType
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> top = getTypeWithProperty(p.name, itype);
if (top != null) {
p.addType(itype, top, relatedType);
} else {
recordInterfaces(itype, relatedType, p);
}
// If this interface invalidated this property, return now.
if (p.skipRenaming) return;
}
if (constructor.isInterface() || constructor.isConstructor()) {
constructor = constructor.getSuperClassConstructor();
} else {
constructor = null;
}
}
}
}
}
/** Implementation of TypeSystem using concrete types. */
private static class ConcreteTypeSystem implements TypeSystem<ConcreteType> {
private final TightenTypes tt;
private int nextUniqueId;
private CodingConvention codingConvention;
private final Set<JSType> invalidatingTypes = Sets.newHashSet();
// An array of native types that are not tracked by type tightening, and
// thus need to be added in if an unknown type is encountered.
private static final JSTypeNative [] nativeTypes = new JSTypeNative[] {
JSTypeNative.BOOLEAN_OBJECT_TYPE,
JSTypeNative.NUMBER_OBJECT_TYPE,
JSTypeNative.STRING_OBJECT_TYPE
};
public ConcreteTypeSystem(TightenTypes tt, CodingConvention convention) {
this.tt = tt;
this.codingConvention = convention;
}
@Override public void addInvalidatingType(JSType type) {
checkState(!type.isUnionType());
invalidatingTypes.add(type);
}
@Override public StaticScope<ConcreteType> getRootScope() {
return tt.getTopScope();
}
@Override public StaticScope<ConcreteType> getFunctionScope(Node decl) {
ConcreteFunctionType func = tt.getConcreteFunction(decl);
return (func != null) ?
func.getScope() : (StaticScope<ConcreteType>) null;
}
@Override
public ConcreteType getType(
StaticScope<ConcreteType> scope, Node node, String prop) {
if (scope != null) {
ConcreteType c = tt.inferConcreteType(
(TightenTypes.ConcreteScope) scope, node);
return maybeAddAutoboxes(c, node, prop);
} else {
return null;
}
}
/**
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>.idGeneratorMap;
}
GlobalNamespace getGlobalNamespace() {
return namespaceForChecks;
}
PreprocessorSymbolTable getPreprocessorSymbolTable() {
return preprocessorSymbolTable;
}
void maybeInitializePreprocessorSymbolTable(AbstractCompiler compiler) {
if (options.ideMode) {
Node root = compiler.getRoot();
if (preprocessorSymbolTable == null ||
preprocessorSymbolTable.getRootNode() != root) {
preprocessorSymbolTable = new PreprocessorSymbolTable(root);
}
}
}
@Override
protected List<PassFactory> getChecks() {
List<PassFactory> checks = Lists.newArrayList();
if (options.closurePass) {
checks.add(closureGoogScopeAliases);
}
if (options.nameAnonymousFunctionsOnly) {
if (options.anonymousFunctionNaming ==
AnonymousFunctionNamingPolicy.MAPPED) {
checks.add(nameMappedAnonymousFunctions);
} else if (options.anonymousFunctionNaming ==
AnonymousFunctionNamingPolicy.UNMAPPED) {
checks.add(nameUnmappedAnonymousFunctions);
}
return checks;
}
checks.add(checkSideEffects);
if (options.checkSuspiciousCode ||
options.enables(DiagnosticGroups.GLOBAL_THIS) ||
options.enables(DiagnosticGroups.DEBUGGER_STATEMENT_PRESENT)) {
checks.add(suspiciousCode);
}
if (options.checkControlStructures
|| options.enables(DiagnosticGroups.ES5_STRICT)) {
checks.add(checkControlStructures);
}
if (options.checkRequires.isOn()) {
checks.add(checkRequires);
}
if (options.checkProvides.isOn()) {
checks.add(checkProvides);
}
// The following passes are more like "preprocessor" passes.
// It's important that they run before most checking passes.
// Perhaps this method should be renamed?
if (options.generateExports) {
checks.add(generateExports);
}
if (options.exportTestFunctions) {
checks.add(exportTestFunctions);
}
if (options.closurePass) {
checks.add(closurePrimitives.makeOneTimePass());
}
if (options.jqueryPass) {
checks.add(jqueryAliases.makeOneTime
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Pass());
}
if (options.closurePass && options.checkMissingGetCssNameLevel.isOn()) {
checks.add(closureCheckGetCssName);
}
if (options.syntheticBlockStartMarker != null) {
// This pass must run before the first fold constants pass.
checks.add(createSyntheticBlocks);
}
checks.add(checkVars);
if (options.computeFunctionSideEffects) {
checks.add(checkRegExp);
}
if (options.aggressiveVarCheck.isOn()) {
checks.add(checkVariableReferences);
}
// This pass should run before types are assigned.
if (options.processObjectPropertyString) {
checks.add(objectPropertyStringPreprocess);
}
if (options.checkTypes || options.inferTypes) {
checks.add(resolveTypes.makeOneTimePass());
checks.add(inferTypes.makeOneTimePass());
if (options.checkTypes) {
checks.add(checkTypes.makeOneTimePass());
} else {
checks.add(inferJsDocInfo.makeOneTimePass());
}
}
if (options.checkUnreachableCode.isOn() ||
(options.checkTypes && options.checkMissingReturn.isOn())) {
checks.add(checkControlFlow);
}
// CheckAccessControls only works if check types is on.
if (options.checkTypes &&
(options.enables(DiagnosticGroups.ACCESS_CONTROLS)
|| options.enables(DiagnosticGroups.CONSTANT_PROPERTY))) {
checks.add(checkAccessControls);
}
if (options.checkGlobalNamesLevel.isOn()) {
checks.add(checkGlobalNames);
}
if (options.enables(DiagnosticGroups.ES5_STRICT) || options.checkCaja) {
checks.add(checkStrictMode);
}
// Replace 'goog.getCssName' before processing defines but after the
// other checks have been done.
if (options.closurePass) {
checks.add(closureReplaceGetCssName);
}
// i18n
// If you want to customize the compiler to use a different i18n pass,
// you can create a PassConfig that calls replacePassFactory
// to replace this.
checks.add(
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>options.messageBundle != null ?
replaceMessages : createEmptyPass("replaceMessages"));
if (options.getTweakProcessing().isOn()) {
checks.add(processTweaks);
}
// Defines in code always need to be processed.
checks.add(processDefines);
if (options.instrumentationTemplate != null ||
options.recordFunctionInformation) {
checks.add(computeFunctionNames);
}
if (options.nameReferenceGraphPath != null &&
!options.nameReferenceGraphPath.isEmpty()) {
checks.add(printNameReferenceGraph);
}
if (options.nameReferenceReportPath != null &&
!options.nameReferenceReportPath.isEmpty()) {
checks.add(printNameReferenceReport);
}
assertAllOneTimePasses(checks);
return checks;
}
@Override
protected List<PassFactory> getOptimizations() {
List<PassFactory> passes = Lists.newArrayList();
passes.add(garbageCollectChecks);
// TODO(nicksantos): The order of these passes makes no sense, and needs
// to be re-arranged.
if (options.runtimeTypeCheck) {
passes.add(runtimeTypeCheck);
}
passes.add(createEmptyPass("beforeStandardOptimizations"));
if (options.replaceIdGenerators) {
passes.add(replaceIdGenerators);
}
// Optimizes references to the arguments variable.
if (options.optimizeArgumentsArray) {
passes.add(optimizeArgumentsArray);
}
// Abstract method removal works best on minimally modified code, and also
// only needs to run once.
if (options.closurePass &&
(options.removeAbstractMethods || options.removeClosureAsserts)) {
passes.add(closureCodeRemoval);
}
// Collapsing properties can undo constant inlining, so we do this before
// the main optimization loop.
if (options.collapseProperties) {
passes.add(collapseProperties);
}
// ReplaceStrings runs after CollapseProperties in order to simplify
// pulling in values of constants defined in enums structures.
if (!options.replaceStringsFunctionDescriptions.isEmpty()) {
passes.add(replaceStrings);
}
// Tighten types based on actual usage.
if (options.tightenTypes) {
passes.add(tightenTypes
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Builder);
}
// Property disambiguation should only run once and needs to be done
// soon after type checking, both so that it can make use of type
// information and so that other passes can take advantage of the renamed
// properties.
if (options.disambiguateProperties) {
passes.add(disambiguateProperties);
}
if (options.computeFunctionSideEffects) {
passes.add(markPureFunctions);
} else if (options.markNoSideEffectCalls) {
// TODO(user) The properties that this pass adds to CALL and NEW
// AST nodes increase the AST's in-memory size. Given that we are
// already running close to our memory limits, we could run into
// trouble if we end up using the @nosideeffects annotation a lot
// or compute @nosideeffects annotations by looking at function
// bodies. It should be easy to propagate @nosideeffects
// annotations as part of passes that depend on this property and
// store the result outside the AST (which would allow garbage
// collection once the pass is done).
passes.add(markNoSideEffectCalls);
}
if (options.chainCalls) {
passes.add(chainCalls);
}
// Constant checking must be done after property collapsing because
// property collapsing can introduce new constants (e.g. enum values).
if (options.inlineConstantVars) {
passes.add(checkConsts);
}
// The Caja library adds properties to Object.prototype, which breaks
// most for-in loops. This adds a check to each loop that skips
// any property matching /___$/.
if (options.ignoreCajaProperties) {
passes.add(ignoreCajaProperties);
}
assertAllOneTimePasses(passes);
if (options.smartNameRemoval || options.reportPath != null) {
passes.addAll(getCodeRemovingPasses());
passes.add(smartNamePass);
}
// This needs to come after the inline constants pass, which is run within
// the code removing passes.
if (options.closurePass) {
passes.add(closureOptimizePrimitives);
}
// TODO(user): This forces a first crack at crossModuleCodeMotion
// before devirtualization. Once certain functions are de
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>virtualized,
// it confuses crossModuleCodeMotion ability to recognized that
// it is recursive.
// TODO(user): This is meant for a temporary quick win.
// In the future, we might want to improve our analysis in
// CrossModuleCodeMotion so we don't need to do this.
if (options.crossModuleCodeMotion) {
passes.add(crossModuleCodeMotion);
}
// Method devirtualization benefits from property disambiguiation so
// it should run after that pass but before passes that do
// optimizations based on global names (like cross module code motion
// and inline functions). Smart Name Removal does better if run before
// this pass.
if (options.devirtualizePrototypeMethods) {
passes.add(devirtualizePrototypeMethods);
}
if (options.customPasses != null) {
passes.add(getCustomPasses(
CustomPassExecutionTime.BEFORE_OPTIMIZATION_LOOP));
}
passes.add(createEmptyPass("beforeMainOptimizations"));
if (options.specializeInitialModule) {
// When specializing the initial module, we want our fixups to be
// as lean as possible, so we run the entire optimization loop to a
// fixed point before specializing, then specialize, and then run the
// main optimization loop again.
passes.addAll(getMainOptimizationLoop());
if (options.crossModuleCodeMotion) {
passes.add(crossModuleCodeMotion);
}
if (options.crossModuleMethodMotion) {
passes.add(crossModuleMethodMotion);
}
passes.add(specializeInitialModule.makeOneTimePass());
}
passes.addAll(getMainOptimizationLoop());
passes.add(createEmptyPass("beforeModuleMotion"));
if (options.crossModuleCodeMotion) {
passes.add(crossModuleCodeMotion);
}
if (options.crossModuleMethodMotion) {
passes.add(crossModuleMethodMotion);
}
passes.add(createEmptyPass("afterModuleMotion"));
// Some optimizations belong outside the loop because running them more
// than once would either have no benefit or be incorrect.
if (options.customPasses != null) {
passes.add(getCustomPasses(
CustomPassExecutionTime.AFTER_OPTIMIZATION_LOOP
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>));
}
if (options.flowSensitiveInlineVariables) {
passes.add(flowSensitiveInlineVariables);
// After inlining some of the variable uses, some variables are unused.
// Re-run remove unused vars to clean it up.
if (options.removeUnusedVars) {
passes.add(removeUnusedVars);
}
}
// Running this pass again is required to have goog.events compile down to
// nothing when compiled on its own.
if (options.smartNameRemoval) {
passes.add(smartNamePass2);
}
if (options.collapseAnonymousFunctions) {
passes.add(collapseAnonymousFunctions);
}
// Move functions before extracting prototype member declarations.
if (options.moveFunctionDeclarations ||
// renamePrefixNamescape relies on moveFunctionDeclarations
// to preserve semantics.
options.renamePrefixNamespace != null) {
passes.add(moveFunctionDeclarations);
}
if (options.anonymousFunctionNaming ==
AnonymousFunctionNamingPolicy.MAPPED) {
passes.add(nameMappedAnonymousFunctions);
}
// The mapped name anonymous function pass makes use of information that
// the extract prototype member declarations pass removes so the former
// happens before the latter.
//
// Extracting prototype properties screws up the heuristic renaming
// policies, so never run it when those policies are requested.
if (options.extractPrototypeMemberDeclarations &&
(options.propertyRenaming != PropertyRenamingPolicy.HEURISTIC &&
options.propertyRenaming !=
PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC)) {
passes.add(extractPrototypeMemberDeclarations);
}
if (options.ambiguateProperties &&
(options.propertyRenaming == PropertyRenamingPolicy.ALL_UNQUOTED)) {
passes.add(ambiguateProperties);
}
if (options.propertyRenaming != PropertyRenamingPolicy.OFF) {
passes.add(renameProperties);
}
// Reserve global names added to the "windows" object.
if (options.reserveRawExports) {
passes.add(gatherRawExports);
}
// This comes after property renaming because quoted property names must
// not be renamed.
if (options.convertToDottedProperties) {
passes.add(convertToDottedProperties);
}
// Property renaming must happen before this pass
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> runs since this
// pass may convert dotted properties into quoted properties. It
// is beneficial to run before alias strings, alias keywords and
// variable renaming.
if (options.rewriteFunctionExpressions) {
passes.add(rewriteFunctionExpressions);
}
// This comes after converting quoted property accesses to dotted property
// accesses in order to avoid aliasing property names.
if (!options.aliasableStrings.isEmpty() || options.aliasAllStrings) {
passes.add(aliasStrings);
}
if (options.aliasExternals) {
passes.add(aliasExternals);
}
if (options.aliasKeywords) {
passes.add(aliasKeywords);
}
// Passes after this point can no longer depend on normalized AST
// assumptions.
passes.add(markUnnormalized);
if (options.coalesceVariableNames) {
passes.add(coalesceVariableNames);
// coalesceVariables creates identity assignments and more redundant code
// that can be removed, rerun the peephole optimizations to clean them
// up.
if (options.foldConstants) {
passes.add(peepholeOptimizations);
}
}
if (options.collapseVariableDeclarations) {
passes.add(exploitAssign);
passes.add(collapseVariableDeclarations);
}
// This pass works best after collapseVariableDeclarations.
passes.add(denormalize);
if (options.instrumentationTemplate != null) {
passes.add(instrumentFunctions);
}
if (options.variableRenaming != VariableRenamingPolicy.ALL) {
// If we're leaving some (or all) variables with their old names,
// then we need to undo any of the markers we added for distinguishing
// local variables ("$$1").
passes.add(invertContextualRenaming);
}
if (options.variableRenaming != VariableRenamingPolicy.OFF) {
passes.add(renameVars);
}
if (options.groupVariableDeclarations) {
passes.add(groupVariableDeclarations);
}
// This pass should run after names stop changing.
if (options.processObjectPropertyString) {
passes.add(objectPropertyStringPostprocess);
}
if (options.labelRenaming) {
passes.add(renameLabels);
}
if (options.foldConstants)
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> {
passes.add(latePeepholeOptimizations);
}
if (options.anonymousFunctionNaming ==
AnonymousFunctionNamingPolicy.UNMAPPED) {
passes.add(nameUnmappedAnonymousFunctions);
}
if (options.renamePrefixNamespace != null) {
if (!GLOBAL_SYMBOL_NAMESPACE_PATTERN.matcher(
options.renamePrefixNamespace).matches()) {
throw new IllegalArgumentException(
"Illegal character in renamePrefixNamespace name: "
+ options.renamePrefixNamespace);
}
passes.add(rescopeGlobalSymbols);
}
passes.add(stripSideEffectProtection);
// Safety checks
passes.add(sanityCheckAst);
passes.add(sanityCheckVars);
return passes;
}
/** Creates the passes for the main optimization loop. */
private List<PassFactory> getMainOptimizationLoop() {
List<PassFactory> passes = Lists.newArrayList();
if (options.inlineGetters) {
passes.add(inlineSimpleMethods);
}
passes.addAll(getCodeRemovingPasses());
if (options.inlineFunctions || options.inlineLocalFunctions) {
passes.add(inlineFunctions);
}
boolean runOptimizeCalls = options.optimizeCalls
|| options.optimizeParameters
|| options.optimizeReturns;
if (options.removeUnusedVars || options.removeUnusedLocalVars) {
if (options.deadAssignmentElimination) {
passes.add(deadAssignmentsElimination);
}
if (!runOptimizeCalls) {
passes.add(removeUnusedVars);
}
}
if (runOptimizeCalls) {
passes.add(optimizeCallsAndRemoveUnusedVars);
}
assertAllLoopablePasses(passes);
return passes;
}
/** Creates several passes aimed at removing code. */
private List<PassFactory> getCodeRemovingPasses() {
List<PassFactory> passes = Lists.newArrayList();
if (options.collapseObjectLiterals && !isInliningForbidden()) {
passes.add(collapseObjectLiterals);
}
if (options.inlineVariables || options.inlineLocalVariables) {
passes.add(inlineVariables);
} else if (options.inlineConstantVars) {
passes.add(inlineConstants);
}
if (options.foldConstants) {
// These used to be one pass.
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> passes.add(minimizeExitPoints);
passes.add(peepholeOptimizations);
}
if (options.removeDeadCode) {
passes.add(removeUnreachableCode);
}
if (options.removeUnusedPrototypeProperties) {
passes.add(removeUnusedPrototypeProperties);
passes.add(removeUnusedClassProperties);
}
assertAllLoopablePasses(passes);
return passes;
}
/**
* Checks for code that is probably wrong (such as stray expressions).
*/
final HotSwapPassFactory checkSideEffects =
new HotSwapPassFactory("checkSideEffects", true) {
@Override
protected HotSwapCompilerPass createInternal(final AbstractCompiler
compiler) {
// The current approach to protecting "hidden" side-effects is to
// wrap them in a function call that is stripped later, this shouldn't
// be done in IDE mode where AST changes may be unexpected.
boolean protectHiddenSideEffects =
options.protectHiddenSideEffects && !options.ideMode;
return new CheckSideEffects(compiler,
options.checkSuspiciousCode ? CheckLevel.WARNING : CheckLevel.OFF,
protectHiddenSideEffects);
}
};
/**
* Checks for code that is probably wrong (such as stray expressions).
*/
final PassFactory stripSideEffectProtection =
new PassFactory("stripSideEffectProtection", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler
compiler) {
return new CheckSideEffects.StripProtection(compiler);
}
};
/**
* Checks for code that is probably wrong (such as stray expressions).
*/
// TODO(bolinfest): Write a CompilerPass for this.
final HotSwapPassFactory suspiciousCode =
new HotSwapPassFactory("suspiciousCode", true) {
@Override
protected HotSwapCompilerPass createInternal(final AbstractCompiler
compiler) {
List<Callback> sharedCallbacks = Lists.newArrayList();
if (options.checkSuspiciousCode) {
sharedCallbacks.add(new CheckAccidentalSemicolon(CheckLevel.WARNING));
}
if (options.enables(DiagnosticGroups.GLOBAL_THIS)) {
sharedCallbacks.add(new CheckGlobalThis(compiler));
}
if (options.enables(DiagnosticGroups.DEBUGGER_STATEMENT_
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>PRESENT)) {
sharedCallbacks.add(new CheckDebuggerStatement(compiler));
}
return combineChecks(compiler, sharedCallbacks);
}
};
/** Verify that all the passes are one-time passes. */
private void assertAllOneTimePasses(List<PassFactory> passes) {
for (PassFactory pass : passes) {
Preconditions.checkState(pass.isOneTimePass());
}
}
/** Verify that all the passes are multi-run passes. */
private void assertAllLoopablePasses(List<PassFactory> passes) {
for (PassFactory pass : passes) {
Preconditions.checkState(!pass.isOneTimePass());
}
}
/** Checks for validity of the control structures. */
final HotSwapPassFactory checkControlStructures =
new HotSwapPassFactory("checkControlStructures", true) {
@Override
protected HotSwapCompilerPass createInternal(AbstractCompiler compiler) {
return new ControlStructureCheck(compiler);
}
};
/** Checks that all constructed classes are goog.require()d. */
final HotSwapPassFactory checkRequires =
new HotSwapPassFactory("checkRequires", true) {
@Override
protected HotSwapCompilerPass createInternal(AbstractCompiler compiler) {
return new CheckRequiresForConstructors(compiler, options.checkRequires);
}
};
/** Makes sure @constructor is paired with goog.provides(). */
final HotSwapPassFactory checkProvides =
new HotSwapPassFactory("checkProvides", true) {
@Override
protected HotSwapCompilerPass createInternal(AbstractCompiler compiler) {
return new CheckProvides(compiler, options.checkProvides);
}
};
private static final DiagnosticType GENERATE_EXPORTS_ERROR =
DiagnosticType.error(
"JSC_GENERATE_EXPORTS_ERROR",
"Exports can only be generated if export symbol/property " +
"functions are set.");
/** Generates exports for @export annotations. */
final PassFactory generateExports =
new PassFactory("generateExports", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
CodingConvention convention = compiler.getCodingConvention();
if (convention.getExportSymbolFunction() != null &&
convention.getExportPropertyFunction() != null) {
return new GenerateExports(compiler,
convention.getExportSymbolFunction(),
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>SwapCompilerPass() {
@Override
public void process(Node externs, Node root) {
Preconditions.checkNotNull(topScope);
Preconditions.checkNotNull(getTypedScopeCreator());
makeInferJsDocInfo(compiler).process(externs, root);
}
@Override
public void hotSwapScript(Node scriptRoot, Node originalRoot) {
makeInferJsDocInfo(compiler).hotSwapScript(scriptRoot, originalRoot);
}
};
}
};
/** Checks type usage */
final HotSwapPassFactory checkTypes =
new HotSwapPassFactory("checkTypes", false) {
@Override
protected HotSwapCompilerPass createInternal(final AbstractCompiler
compiler) {
return new HotSwapCompilerPass() {
@Override
public void process(Node externs, Node root) {
Preconditions.checkNotNull(topScope);
Preconditions.checkNotNull(getTypedScopeCreator());
TypeCheck check = makeTypeCheck(compiler);
check.process(externs, root);
compiler.getErrorManager().setTypedPercent(check.getTypedPercent());
}
@Override
public void hotSwapScript(Node scriptRoot, Node originalRoot) {
makeTypeCheck(compiler).check(scriptRoot, false);
}
};
}
};
/**
* Checks possible execution paths of the program for problems: missing return
* statements and dead code.
*/
final HotSwapPassFactory checkControlFlow =
new HotSwapPassFactory("checkControlFlow", true) {
@Override
protected HotSwapCompilerPass createInternal(AbstractCompiler compiler) {
List<Callback> callbacks = Lists.newArrayList();
if (options.checkUnreachableCode.isOn()) {
callbacks.add(
new CheckUnreachableCode(compiler, options.checkUnreachableCode));
}
if (options.checkMissingReturn.isOn() && options.checkTypes) {
callbacks.add(
new CheckMissingReturn(compiler, options.checkMissingReturn));
}
return combineChecks(compiler, callbacks);
}
};
/** Checks access controls. Depends on type-inference. */
final HotSwapPassFactory checkAccessControls =
new HotSwapPassFactory("checkAccessControls", true) {
@Override
protected HotSwapCompilerPass createInternal(AbstractCompiler compiler) {
return new CheckAccessControls(compiler);
}
};
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Restricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
for (JSType element : alternates) {
TypePair p = element.getTypesUnderShallowInequality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
}
if (p.typeB != null) {
thatRestricted.addAlternate(p.typeB);
}
}
return new TypePair(
thisRestricted.build(),
thatRestricted.build());
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseUnionType(this);
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
setResolvedTypeInternal(this); // for circularly defined types.
boolean changed = false;
ImmutableList.Builder<JSType> resolvedTypes = ImmutableList.builder();
for (JSType alternate : alternates) {
JSType newAlternate = alternate.resolve(t, scope);
changed |= (alternate != newAlternate);
resolvedTypes.add(alternate);
}
if (changed) {
Collection<JSType> newAlternates = resolvedTypes.build();
Preconditions.checkState(
newAlternates.hashCode() == this.hashcode);
alternates = newAlternates;
}
return this;
}
@Override
public String toDebugHashCodeString() {
List<String> hashCodes = Lists.newArrayList();
for (JSType a : alternates) {
hashCodes.add(a.toDebugHashCodeString());
}
return "{(" + Joiner.on(",").join(hashCodes) + ")}";
}
@Override
public boolean setValidator(Predicate<JSType> validator) {
for (JSType a : alternates) {
a.setValidator(validator);
}
return true;
}
@Override
public JSType collapseUnion() {
JSType currentValue = null;
ObjectType currentCommonSuper = null;
for (JSType a : alternates) {
if (a.isUnknownType()) {
return getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
ObjectType obj = a.toObjectType();
if (obj == null) {
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>();
continue retry;
case EXTERNS:
if (!jsdocBuilder.recordExterns()) {
parser.addParserWarning("msg.jsdoc.externs",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case JAVA_DISPATCH:
if (!jsdocBuilder.recordJavaDispatch()) {
parser.addParserWarning("msg.jsdoc.javadispatch",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case EXTENDS:
case IMPLEMENTS:
skipEOLs();
token = next();
lineno = stream.getLineno();
charno = stream.getCharno();
boolean matchingRc = false;
if (token == JsDocToken.LC) {
token = next();
matchingRc = true;
}
if (token == JsDocToken.STRING) {
Node typeNode = parseAndRecordTypeNameNode(
token, lineno, charno, matchingRc);
lineno = stream.getLineno();
charno = stream.getCharno();
typeNode = wrapNode(Token.BANG, typeNode);
if (typeNode != null && !matchingRc) {
typeNode.putBooleanProp(Node.BRACELESS_TYPE, true);
}
type = createJSTypeExpression(typeNode);
if (annotation == Annotation.EXTENDS) {
// record the extended type, check later
extendedTypes.add(new ExtendedTypeInfo(
type, stream.getLineno(), stream.getCharno()));
} else {
Preconditions.checkState(
annotation == Annotation.IMPLEMENTS);
if (!jsdocBuilder.recordImplementedInterface(type)) {
parser.addTypeWarning("msg.jsdoc.implements.duplicate",
lineno, charno);
}
}
token = next();
if (matchingRc) {
if (token != JsDocToken.RC) {
parser.addTypeWarning("msg.jsdoc.missing.rc",
stream.getLineno(), stream.getCharno());
}
} else if (token != JsDocToken.EOL &&
token != JsDocToken.EOF && token != JsDocToken.EOC) {
parser.addTypeWarning("
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> Set<String> suppressions = new HashSet<String>();
while (true) {
if (match(JsDocToken.STRING)) {
String name = stream.getString();
if (!suppressionNames.contains(name)) {
parser.addParserWarning("msg.jsdoc.suppress.unknown", name,
stream.getLineno(), stream.getCharno());
}
suppressions.add(stream.getString());
token = next();
} else {
parser.addParserWarning("msg.jsdoc.suppress",
stream.getLineno(), stream.getCharno());
return token;
}
if (match(JsDocToken.PIPE)) {
token = next();
} else {
break;
}
}
if (!match(JsDocToken.RC)) {
parser.addParserWarning("msg.jsdoc.suppress",
stream.getLineno(), stream.getCharno());
} else {
token = next();
if (!jsdocBuilder.recordSuppressions(suppressions)) {
parser.addParserWarning("msg.jsdoc.suppress.duplicate",
stream.getLineno(), stream.getCharno());
}
}
}
return token;
}
/**
* Parse a {@code @modifies} tag of the form
* {@code @modifies{this|arguments|param}}.
*
* @param token The current token.
*/
private JsDocToken parseModifiesTag(JsDocToken token) {
if (token == JsDocToken.LC) {
Set<String> modifies = new HashSet<String>();
while (true) {
if (match(JsDocToken.STRING)) {
String name = stream.getString();
if (!modifiesAnnotationKeywords.contains(name)
&& !jsdocBuilder.hasParameter(name)) {
parser.addParserWarning("msg.jsdoc.modifies.unknown", name,
stream.getLineno(), stream.getCharno());
}
modifies.add(stream.getString());
token = next();
} else {
parser.addParserWarning("msg.jsdoc.modifies",
stream.getLineno(), stream.getCharno());
return token;
}
if (match(JsDocToken.PIPE))
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Annotations()}. Edges' annotation values are cleared.
*/
public final void pushEdgeAnnotations() {
if (edgeAnnotationStack == null) {
edgeAnnotationStack = Lists.newLinkedList();
}
pushAnnotations(edgeAnnotationStack, getEdges());
}
/**
* Restores edges' annotation values to state before last
* {@link #pushEdgeAnnotations()}.
*/
public final void popEdgeAnnotations() {
Preconditions.checkNotNull(edgeAnnotationStack,
"Popping edge annotations without pushing.");
popAnnotations(edgeAnnotationStack);
}
/**
* A generic edge.
*
* @param <N> Value type that the graph node stores.
* @param <E> Value type that the graph edge stores.
*/
public interface GraphEdge<N, E> extends Annotatable {
/**
* Retrieves the edge's value.
*
* @return The value.
*/
E getValue();
GraphNode<N, E> getNodeA();
GraphNode<N, E> getNodeB();
}
/**
* A simple implementation of SubGraph that calculates adjacency by iterating
* over a node's neighbors.
*/
class SimpleSubGraph<N, E> implements SubGraph<N, E> {
private Graph<N, E> graph;
private List<GraphNode<N, E>> nodes = Lists.newArrayList();
SimpleSubGraph(Graph<N, E> graph) {
this.graph = graph;
}
@Override
public boolean isIndependentOf(N value) {
GraphNode<N, E> node = graph.getNode(value);
for (GraphNode<N, E> n : nodes) {
if (graph.getNeighborNodes(n.getValue()).contains(node)) {
return false;
}
}
return true;
}
@Override
public void addNode(N value) {
nodes.add(graph.getNodeOrFail(value));
}
}
/**
* Pushes a new list on stack and stores nodes annotations in the new list.
* Clears objects' annotations as well.
*/
private static void pushAnnotations(
Deque<GraphAnnotationState> stack,
Collection<? extends Annotatable> haveAnnotations) {
stack.push(new GraphAnnotationState(haveAnnotations.size()));
for (Annotatable h : haveAnnotations
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>) {
stack.peek().add(new AnnotationState(h, h.getAnnotation()));
h.setAnnotation(null);
}
}
/**
* Restores the node annotations on the top of stack and pops stack.
*/
private static void popAnnotations(Deque<GraphAnnotationState> stack) {
for (AnnotationState as : stack.pop()) {
as.first.setAnnotation(as.second);
}
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>.setSourceFile(file);
}
/** Returns the SourceAst object on which this input is based. */
public SourceAst getSourceAst() {
return ast;
}
/** Sets an error manager for routing error messages. */
public void setErrorManager(ErrorManager errorManager) {
this.errorManager = errorManager;
}
/** Sets an abstract compiler for doing parsing. */
public void setCompiler(AbstractCompiler compiler) {
this.compiler = compiler;
setErrorManager(compiler.getErrorManager());
}
/** Gets a list of types depended on by this input. */
@Override
public Collection<String> getRequires() {
Preconditions.checkNotNull(errorManager,
"Expected setErrorManager to be called first");
try {
regenerateDependencyInfoIfNecessary();
return Collections.<String>unmodifiableSet(requires);
} catch (IOException e) {
errorManager.report(CheckLevel.ERROR,
JSError.make(AbstractCompiler.READ_ERROR, getName()));
return ImmutableList.<String>of();
}
}
/** Gets a list of types provided by this input. */
@Override
public Collection<String> getProvides() {
Preconditions.checkNotNull(errorManager,
"Expected setErrorManager to be called first");
try {
regenerateDependencyInfoIfNecessary();
return Collections.<String>unmodifiableSet(provides);
} catch (IOException e) {
errorManager.report(CheckLevel.ERROR,
JSError.make(AbstractCompiler.READ_ERROR, getName()));
return ImmutableList.<String>of();
}
}
// TODO(nicksantos): Remove addProvide/addRequire/removeRequire once
// there is better support for discovering non-closure dependencies.
void addProvide(String provide) {
getProvides();
provides.add(provide);
}
void addRequire(String require) {
getRequires();
requires.add(require);
}
public void removeRequire(String require) {
getRequires();
requires.remove(require);
}
/**
* Regenerates the provides/requires if we need to do so.
*/
private void regenerateDependencyInfoIfNecessary() throws IOException {
// If the code is NOT a JsAst, then it was not originally JS code.
// Look at the Ast for dependency info.
if (!(ast instanceof
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> JsAst)) {
Preconditions.checkNotNull(compiler,
"Expected setCompiler to be called first");
DepsFinder finder = new DepsFinder();
Node root = getAstRoot(compiler);
if (root == null) {
return;
}
finder.visitTree(getAstRoot(compiler));
// TODO(nicksantos|user): This caching behavior is a bit
// odd, and only works if you assume the exact call flow that
// clients are currently using. In that flow, they call
// getProvides(), then remove the goog.provide calls from the
// AST, and then call getProvides() again.
//
// This won't work for any other call flow, or any sort of incremental
// compilation scheme. The API needs to be fixed so callers aren't
// doing weird things like this, and then we should get rid of the
// multiple-scan strategy.
provides.addAll(finder.provides);
requires.addAll(finder.requires);
} else {
// Otherwise, look at the source code.
if (!generatedDependencyInfoFromSource) {
// Note: it's ok to use getName() instead of
// getPathRelativeToClosureBase() here because we're not using
// this to generate deps files. (We're only using it for
// symbol dependencies.)
DependencyInfo info = (new JsFileParser(errorManager)).parseFile(
getName(), getName(), getCode());
provides.addAll(info.getProvides());
requires.addAll(info.getRequires());
generatedDependencyInfoFromSource = true;
}
}
}
private static class DepsFinder {
private final List<String> provides = Lists.newArrayList();
private final List<String> requires = Lists.newArrayList();
private final CodingConvention codingConvention =
new ClosureCodingConvention();
void visitTree(Node n) {
visitSubtree(n, null);
}
void visitSubtree(Node n, Node parent) {
if (n.isCall()) {
String require =
codingConvention.extractClassNameIfRequire(n, parent);
if (require != null) {
requires.add(require);
}
String provide =
codingConvention.extractClassNameIfProvide(n, parent);
if (provide != null) {
provides.add(provide);
}
return;
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>();
}
/**
* @return Whether the node is used as a statement.
*/
static boolean isStatement(Node n) {
return isStatementParent(n.getParent());
}
static boolean isStatementParent(Node parent) {
// It is not possible to determine definitely if a node is a statement
// or not if it is not part of the AST. A FUNCTION node can be
// either part of an expression or a statement.
Preconditions.checkState(parent != null);
switch (parent.getType()) {
case Token.SCRIPT:
case Token.BLOCK:
case Token.LABEL:
return true;
default:
return false;
}
}
/** Whether the node is part of a switch statement. */
static boolean isSwitchCase(Node n) {
return n.isCase() || n.isDefaultCase();
}
/**
* @return Whether the name is a reference to a variable, function or
* function parameter (not a label or a empty function expression name).
*/
static boolean isReferenceName(Node n) {
return n.isName() && !n.getString().isEmpty();
}
/** Whether the child node is the FINALLY block of a try. */
static boolean isTryFinallyNode(Node parent, Node child) {
return parent.isTry() && parent.getChildCount() == 3
&& child == parent.getLastChild();
}
/** Whether the node is a CATCH container BLOCK. */
static boolean isTryCatchNodeContainer(Node n) {
Node parent = n.getParent();
return parent.isTry()
&& parent.getFirstChild().getNext() == n;
}
/** Safely remove children while maintaining a valid node structure. */
static void removeChild(Node parent, Node node) {
if (isTryFinallyNode(parent, node)) {
if (NodeUtil.hasCatchHandler(getCatchBlock(parent))) {
// A finally can only be removed if there is a catch.
parent.removeChild(node);
} else {
// Otherwise only its children can be removed.
node.detachChildren();
}
} else if (node.isCatch()) {
// The CATCH can can only be removed if there is a finally clause.
Node tryNode = node.getParent().getParent();
Preconditions.checkState
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> the block was removed.
*/
static boolean tryMergeBlock(Node block) {
Preconditions.checkState(block.isBlock());
Node parent = block.getParent();
// Try to remove the block if its parent is a block/script or if its
// parent is label and it has exactly one child.
if (isStatementBlock(parent)) {
Node previous = block;
while (block.hasChildren()) {
Node child = block.removeFirstChild();
parent.addChildAfter(child, previous);
previous = child;
}
parent.removeChild(block);
return true;
} else {
return false;
}
}
/**
* @param node A node
* @return Whether the call is a NEW or CALL node.
*/
static boolean isCallOrNew(Node node) {
return node.isCall() || node.isNew();
}
/**
* Return a BLOCK node for the given FUNCTION node.
*/
static Node getFunctionBody(Node fn) {
Preconditions.checkArgument(fn.isFunction());
return fn.getLastChild();
}
/**
* Is this node or any of its children a CALL?
*/
static boolean containsCall(Node n) {
return containsType(n, Token.CALL);
}
/**
* Is this node a function declaration? A function declaration is a function
* that has a name that is added to the current scope (i.e. a function that
* is not part of a expression; see {@link #isFunctionExpression}).
*/
static boolean isFunctionDeclaration(Node n) {
return n.isFunction() && isStatement(n);
}
/**
* Is this node a hoisted function declaration? A function declaration in the
* scope root is hoisted to the top of the scope.
* See {@link #isFunctionDeclaration}).
*/
static boolean isHoistedFunctionDeclaration(Node n) {
return isFunctionDeclaration(n)
&& (n.getParent().isScript()
|| n.getParent().getParent().isFunction());
}
/**
* Is a FUNCTION node an function expression? An function expression is one
* that has either no name or a name that is not added to the current scope.
*
* <p>Some examples of function expressions:
* <pre>
* (function () {})
* (
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>function f() {})()
* [ function f() {} ]
* var f = function f() {};
* for (function f() {};;) {}
* </pre>
*
* <p>Some examples of functions that are <em>not</em> expressions:
* <pre>
* function f() {}
* if (x); else function f() {}
* for (;;) { function f() {} }
* </pre>
*
* @param n A node
* @return Whether n is an function used within an expression.
*/
static boolean isFunctionExpression(Node n) {
return n.isFunction() && !isStatement(n);
}
/**
* Determines if a node is a function expression that has an empty body.
*
* @param node a node
* @return whether the given node is a function expression that is empty
*/
static boolean isEmptyFunctionExpression(Node node) {
return isFunctionExpression(node) && isEmptyBlock(node.getLastChild());
}
/**
* Determines if a function takes a variable number of arguments by
* looking for references to the "arguments" var_args object.
*/
static boolean isVarArgsFunction(Node function) {
Preconditions.checkArgument(function.isFunction());
return isNameReferenced(
function.getLastChild(),
"arguments",
MATCH_NOT_FUNCTION);
}
/**
* @return Whether node is a call to methodName.
* a.f(...)
* a['f'](...)
*/
static boolean isObjectCallMethod(Node callNode, String methodName) {
if (callNode.isCall()) {
Node functionIndentifyingExpression = callNode.getFirstChild();
if (isGet(functionIndentifyingExpression)) {
Node last = functionIndentifyingExpression.getLastChild();
if (last != null && last.isString()) {
String propName = last.getString();
return (propName.equals(methodName));
}
}
}
return false;
}
/**
* @return Whether the callNode represents an expression in the form of:
* x.call(...)
* x['call'](...)
*/
static boolean isFunctionObjectCall(Node callNode) {
return isObjectCallMethod(callNode, "call");
}
/**
* @return Whether the call
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> them are duplicates of
// one another.
int currentIndex = 0;
Iterator<JSType> it = alternates.iterator();
while (it.hasNext()) {
JSType current = it.next();
// Unknown and NoResolved types may just be names that haven't
// been resolved yet. So keep these in the union, and just use
// equality checking for simple de-duping.
if (alternate.isUnknownType() ||
current.isUnknownType() ||
alternate.isNoResolvedType() ||
current.isNoResolvedType()) {
if (alternate.isEquivalentTo(current)) {
// Alternate is unnecessary.
return this;
}
} else {
if (alternate.isSubtype(current)) {
// Alternate is unnecessary.
return this;
} else if (current.isSubtype(alternate)) {
// Alternate makes current obsolete
it.remove();
if (currentIndex == functionTypePosition) {
functionTypePosition = -1;
} else if (currentIndex < functionTypePosition) {
functionTypePosition--;
currentIndex--;
}
}
}
currentIndex++;
}
if (alternate.isFunctionType()) {
// See the comments on functionTypePosition above.
Preconditions.checkState(functionTypePosition == -1);
functionTypePosition = alternates.size();
}
alternates.add(alternate);
result = null; // invalidate the memoized result
}
} else {
result = null;
}
return this;
}
/**
* Reduce the alternates into a non-union type.
* If the alternates can't be accurately represented with a non-union
* type, return null.
*/
private JSType reduceAlternatesWithoutUnion() {
if (isAllType) {
return registry.getNativeType(ALL_TYPE);
} else if (isNativeUnknownType) {
if (areAllUnknownsChecked) {
return registry.getNativeType(CHECKED_UNKNOWN_TYPE);
} else {
return registry.getNativeType(UNKNOWN_TYPE);
}
} else {
int size = alternates.size();
if (size > maxUnionSize) {
return registry.getNativeType(UNKNOWN_TYPE);
} else if (size > 1) {
return null;
} else
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> void visit(NodeTraversal t, Node n, Node parent) {
if (!n.isCall()) {
return;
}
String callName = n.getFirstChild().getQualifiedName();
TweakFunction tweakFunc = TWEAK_FUNCTIONS_MAP.get(callName);
if (tweakFunc == null) {
return;
}
if (tweakFunc == TweakFunction.GET_COMPILER_OVERRIDES) {
getOverridesCalls.add(
new TweakFunctionCall(t.getSourceName(), tweakFunc, n));
return;
}
// Ensure the first parameter (the tweak ID) is a string literal.
Node tweakIdNode = n.getFirstChild().getNext();
if (!tweakIdNode.isString()) {
compiler.report(t.makeError(tweakIdNode, NON_LITERAL_TWEAK_ID_ERROR));
return;
}
String tweakId = tweakIdNode.getString();
// Make sure there is a TweakInfo structure for it.
TweakInfo tweakInfo = allTweaks.get(tweakId);
if (tweakInfo == null) {
tweakInfo = new TweakInfo(tweakId);
allTweaks.put(tweakId, tweakInfo);
}
switch (tweakFunc) {
case REGISTER_BOOLEAN:
case REGISTER_NUMBER:
case REGISTER_STRING:
// Ensure the ID contains only valid characters.
if (!ID_MATCHER.matchesAllOf(tweakId)) {
compiler.report(t.makeError(tweakIdNode, INVALID_TWEAK_ID_ERROR));
}
// Ensure tweaks are registered in the global scope.
if (!t.inGlobalScope()) {
compiler.report(
t.makeError(n, NON_GLOBAL_TWEAK_INIT_ERROR, tweakId));
break;
}
// Ensure tweaks are registered only once.
if (tweakInfo.isRegistered()) {
compiler.report(
t.makeError(n, TWEAK_MULTIPLY_REGISTERED_ERROR, tweakId));
break;
}
Node tweakDefaultValueNode = tweakIdNode.getNext().getNext();
tweakInfo.addRegisterCall(t.getSourceName(), tweakFunc, n,
tweakDefaultValueNode);
break;
case OVERRIDE_DEFAULT_VALUE
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>AllTypeWarnings();
} else {
emitUnknownTweakErrors();
}
}
/**
* Emits a warning for each default value parameter that has the wrong type
* and for each getter function that was used for the wrong type of tweak.
*/
void emitAllTypeWarnings() {
for (TweakFunctionCall call : functionCalls) {
Node valueNode = call.valueNode;
TweakFunction tweakFunc = call.tweakFunc;
TweakFunction registerFunc = registerCall.tweakFunc;
if (valueNode != null) {
// For register* and overrideDefaultValue calls, ensure the default
// value is a literal of the correct type.
if (!registerFunc.isValidNodeType(valueNode.getType())) {
compiler.report(JSError.make(call.sourceName,
valueNode, INVALID_TWEAK_DEFAULT_VALUE_WARNING,
tweakId, registerFunc.getName(),
registerFunc.getExpectedTypeName()));
}
} else if (tweakFunc.isGetterFunction()) {
// For getter calls, ensure the correct getter was used.
if (!tweakFunc.isCorrectRegisterFunction(registerFunc)) {
compiler.report(JSError.make(call.sourceName,
call.callNode, TWEAK_WRONG_GETTER_TYPE_WARNING,
tweakFunc.getName(), registerFunc.getName()));
}
}
}
}
/**
* Emits an error for each function call that was found.
*/
void emitUnknownTweakErrors() {
for (TweakFunctionCall call : functionCalls) {
compiler.report(JSError.make(call.sourceName,
call.getIdNode(), UNKNOWN_TWEAK_WARNING, tweakId));
}
}
void addRegisterCall(String sourceName, TweakFunction tweakFunc,
Node callNode, Node defaultValueNode) {
registerCall = new TweakFunctionCall(sourceName, tweakFunc, callNode,
defaultValueNode);
functionCalls.add(registerCall);
}
void addOverrideDefaultValueCall(String sourceName,
TweakFunction tweakFunc, Node callNode, Node defaultValueNode) {
functionCalls.add(new TweakFunctionCall(sourceName, tweakFunc, callNode,
defaultValueNode));
this.defaultValueNode = defaultValueNode;
}
void addGetterCall(
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>String sourceName, TweakFunction tweakFunc,
Node callNode) {
functionCalls.add(new TweakFunctionCall(sourceName, tweakFunc, callNode));
}
boolean isRegistered() {
return registerCall != null;
}
Node getDefaultValueNode() {
Preconditions.checkState(isRegistered());
// Use calls to goog.tweak.overrideDefaultValue() first.
if (defaultValueNode != null) {
return defaultValueNode;
}
// Use the value passed to the register function next.
if (registerCall.valueNode != null) {
return registerCall.valueNode;
}
// Otherwise, use the default value for the tweak's type.
return registerCall.tweakFunc.createDefaultValueNode();
}
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> (currentParam.getNext() != null && newParam.isVarArgs()) {
newParam.setVarArgs(false);
newParam.setOptionalArg(true);
}
} else {
warnedAboutArgList |= addParameter(
paramBuilder,
typeRegistry.getNativeType(UNKNOWN_TYPE),
warnedAboutArgList,
codingConvention.isOptionalParameter(currentParam) ||
oldParamsListHitOptArgs,
codingConvention.isVarArgsParameter(currentParam));
}
}
parametersNode = paramBuilder.build();
}
return this;
}
/**
* Infer the return type from JSDocInfo.
*/
FunctionTypeBuilder inferReturnType(@Nullable JSDocInfo info) {
if (info != null && info.hasReturnType()) {
returnType = info.getReturnType().evaluate(scope, typeRegistry);
returnTypeInferred = false;
}
if (templateTypeName != null &&
returnType != null &&
returnType.restrictByNotNullOrUndefined().isTemplateType()) {
reportError(TEMPLATE_TYPE_EXPECTED, fnName);
}
return this;
}
/**
* Infer the role of the function (whether it's a constructor or interface)
* and what it inherits from in JSDocInfo.
*/
FunctionTypeBuilder inferInheritance(@Nullable JSDocInfo info) {
if (info != null) {
isConstructor = info.isConstructor();
isInterface = info.isInterface();
// base type
if (info.hasBaseType()) {
if (isConstructor) {
JSType maybeBaseType =
info.getBaseType().evaluate(scope, typeRegistry);
if (maybeBaseType != null &&
maybeBaseType.setValidator(new ExtendedTypeValidator())) {
baseType = (ObjectType) maybeBaseType;
}
} else {
reportWarning(EXTENDS_WITHOUT_TYPEDEF, fnName);
}
}
// implemented interfaces
if (isConstructor || isInterface) {
implementedInterfaces = Lists.newArrayList();
for (JSTypeExpression t : info.getImplementedInterfaces()) {
JSType maybeInterType = t.evaluate(scope, typeRegistry);
if (maybeInterType != null &&
maybeInterType.setValidator(new ImplementedTypeValidator())) {
implementedInterfaces.add((ObjectType) maybeInterType);
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> }
} else if (info.getImplementedInterfaceCount() > 0) {
reportWarning(IMPLEMENTS_WITHOUT_CONSTRUCTOR, fnName);
}
// extended interfaces (for interface only)
if (isInterface) {
extendedInterfaces = Lists.newArrayList();
for (JSTypeExpression t : info.getExtendedInterfaces()) {
JSType maybeInterfaceType = t.evaluate(scope, typeRegistry);
if (maybeInterfaceType != null &&
maybeInterfaceType.setValidator(new ExtendedTypeValidator())) {
extendedInterfaces.add((ObjectType) maybeInterfaceType);
}
}
}
}
return this;
}
/**
* Infers the type of {@code this}.
* @param type The type of this if the info is missing.
*/
FunctionTypeBuilder inferThisType(JSDocInfo info, JSType type) {
// Look at the @this annotation first.
inferThisType(info);
if (thisType == null) {
ObjectType objType = ObjectType.cast(type);
if (objType != null && (info == null || !info.hasType())) {
thisType = objType;
}
}
return this;
}
/**
* Infers the type of {@code this}.
* @param info The JSDocInfo for this function.
*/
FunctionTypeBuilder inferThisType(JSDocInfo info) {
ObjectType maybeThisType = null;
if (info != null && info.hasThisType()) {
maybeThisType = ObjectType.cast(
info.getThisType().evaluate(scope, typeRegistry));
}
if (maybeThisType != null) {
thisType = maybeThisType;
thisType.setValidator(new ThisTypeValidator());
}
return this;
}
/**
* Infer the parameter types from the doc info alone.
*/
FunctionTypeBuilder inferParameterTypes(JSDocInfo info) {
// Create a fake args parent.
Node lp = IR.paramList();
for (String name : info.getParameterNames()) {
lp.addChildToBack(IR.name(name));
}
return inferParameterTypes(lp, info);
}
/**
* Infer the parameter types from the list of argument names and
* the doc info.
*/
FunctionTypeBuilder inferParameter
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> true;
}
}
}
return false;
}
}
/** Holds data dynamically inferred about functions. */
static interface FunctionContents {
/** Returns the source node of this function. May be null. */
Node getSourceNode();
/** Returns if the function may be in externs. */
boolean mayBeFromExterns();
/** Returns if a return of a real value (not undefined) appears. */
boolean mayHaveNonEmptyReturns();
/** Gets a list of variables in this scope that are escaped. */
Iterable<String> getEscapedVarNames();
}
static class UnknownFunctionContents implements FunctionContents {
private static UnknownFunctionContents singleton =
new UnknownFunctionContents();
static FunctionContents get() {
return singleton;
}
@Override
public Node getSourceNode() {
return null;
}
@Override
public boolean mayBeFromExterns() {
return true;
}
@Override
public boolean mayHaveNonEmptyReturns() {
return true;
}
@Override
public Iterable<String> getEscapedVarNames() {
return ImmutableList.of();
}
}
static class AstFunctionContents implements FunctionContents {
private final Node n;
private boolean hasNonEmptyReturns = false;
private Set<String> escapedVarNames;
AstFunctionContents(Node n) {
this.n = n;
}
@Override
public Node getSourceNode() {
return n;
}
@Override
public boolean mayBeFromExterns() {
return n.isFromExterns();
}
@Override
public boolean mayHaveNonEmptyReturns() {
return hasNonEmptyReturns;
}
void recordNonEmptyReturn() {
hasNonEmptyReturns = true;
}
@Override
public Iterable<String> getEscapedVarNames() {
return escapedVarNames == null
? ImmutableList.<String>of() : escapedVarNames;
}
void recordEscapedVarName(String name) {
if (escapedVarNames == null) {
escapedVarNames = Sets.newHashSet();
}
escapedVarNames.add(name);
}
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>ClassNameIfGoog(Node node, Node parent,
String functionName){
String className = null;
if (NodeUtil.isExprCall(parent)) {
Node callee = node.getFirstChild();
if (callee != null && callee.isGetProp()) {
String qualifiedName = callee.getQualifiedName();
if (functionName.equals(qualifiedName)) {
Node target = callee.getNext();
if (target != null && target.isString()) {
className = target.getString();
}
}
}
}
return className;
}
/**
* Use closure's implementation.
* @return closure's function name for exporting properties.
*/
@Override
public String getExportPropertyFunction() {
return "goog.exportProperty";
}
/**
* Use closure's implementation.
* @return closure's function name for exporting symbols.
*/
@Override
public String getExportSymbolFunction() {
return "goog.exportSymbol";
}
@Override
public List<String> identifyTypeDeclarationCall(Node n) {
Node callName = n.getFirstChild();
if ("goog.addDependency".equals(callName.getQualifiedName()) &&
n.getChildCount() >= 3) {
Node typeArray = callName.getNext().getNext();
if (typeArray.isArrayLit()) {
List<String> typeNames = Lists.newArrayList();
for (Node name = typeArray.getFirstChild(); name != null;
name = name.getNext()) {
if (name.isString()) {
typeNames.add(name.getString());
}
}
return typeNames;
}
}
return null;
}
@Override
public String getAbstractMethodName() {
return "goog.abstractMethod";
}
@Override
public String getSingletonGetterClassName(Node callNode) {
Node callArg = callNode.getFirstChild();
String callName = callArg.getQualifiedName();
// Use both the original name and the post-CollapseProperties name.
if (!("goog.addSingletonGetter".equals(callName) ||
"goog$addSingletonGetter".equals(callName)) ||
callNode.getChildCount() != 2) {
return null;
}
return callArg.getNext().getQualifiedName();
}
@Override
public void applySingletonGetter
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> Map<String, Node> provides = Maps.newHashMap();
private final Map<String, Node> ctors = Maps.newHashMap();
private final CodingConvention convention;
CheckProvidesCallback(CodingConvention convention){
this.convention = convention;
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
case Token.CALL:
String providedClassName =
codingConvention.extractClassNameIfProvide(n, parent);
if (providedClassName != null) {
provides.put(providedClassName, n);
}
break;
case Token.FUNCTION:
visitFunctionNode(n, parent);
break;
case Token.SCRIPT:
visitScriptNode(t, n);
}
}
private void visitFunctionNode(Node n, Node parent) {
Node name = null;
JSDocInfo info = parent.getJSDocInfo();
if (info != null && info.isConstructor()) {
name = parent.getFirstChild();
} else {
// look to the child, maybe it's a named function
info = n.getJSDocInfo();
if (info != null && info.isConstructor()) {
name = n.getFirstChild();
}
}
if (name != null && name.isQualifiedName()) {
String qualifiedName = name.getQualifiedName();
if (!this.convention.isPrivate(qualifiedName)) {
Visibility visibility = info.getVisibility();
if (!visibility.equals(JSDocInfo.Visibility.PRIVATE)) {
ctors.put(qualifiedName, name);
}
}
}
}
private void visitScriptNode(NodeTraversal t, Node n) {
for (Map.Entry<String, Node> ctorEntry : ctors.entrySet()) {
if (!provides.containsKey(ctorEntry.getKey())) {
compiler.report(
t.makeError(ctorEntry.getValue(), checkLevel,
MISSING_PROVIDE_WARNING, ctorEntry.getKey()));
}
}
provides.clear();
ctors.clear();
}
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>GraphNode<Node, Branch> candidate : cfg.getDirectedGraphNodes()) {
if (!nodePriorities.containsKey(candidate)) {
nodePriorities.put(candidate, ++priorityCounter);
}
}
// Again, the implicit return node is always last.
nodePriorities.put(cfg.getImplicitReturn(), ++priorityCounter);
}
/**
* Given an entry node, find all the nodes reachable from that node
* and prioritize them.
*/
private void prioritizeFromEntryNode(DiGraphNode<Node, Branch> entry) {
PriorityQueue<DiGraphNode<Node, Branch>> worklist =
new PriorityQueue<DiGraphNode<Node, Branch>>(10, priorityComparator);
worklist.add(entry);
while (!worklist.isEmpty()) {
DiGraphNode<Node, Branch> current = worklist.remove();
if (nodePriorities.containsKey(current)) {
continue;
}
nodePriorities.put(current, ++priorityCounter);
List<DiGraphNode<Node, Branch>> successors =
cfg.getDirectedSuccNodes(current);
for (DiGraphNode<Node, Branch> candidate : successors) {
worklist.add(candidate);
}
}
}
@Override
public boolean shouldTraverse(
NodeTraversal nodeTraversal, Node n, Node parent) {
astPosition.put(n, astPositionCounter++);
switch (n.getType()) {
case Token.FUNCTION:
if (shouldTraverseFunctions || n == cfg.getEntry().getValue()) {
exceptionHandler.push(n);
return true;
}
return false;
case Token.TRY:
exceptionHandler.push(n);
return true;
}
/*
* We are going to stop the traversal depending on what the node's parent
* is.
*
* We are only interested in adding edges between nodes that change control
* flow. The most obvious ones are loops and IF-ELSE's. A statement
* transfers control to its next sibling.
*
* In case of an expression tree, there is no control flow within the tree
* even when there are short circuited operators and conditionals. When we
* are doing data flow analysis, we will simply synthesize lattices up the
* expression tree by finding the meet at
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Mode mode) {
this.resolveMode = mode;
}
ResolveMode getResolveMode() {
return resolveMode;
}
public ErrorReporter getErrorReporter() {
return reporter;
}
public boolean shouldTolerateUndefinedValues() {
return tolerateUndefinedValues;
}
/**
* Reset to run the TypeCheck pass.
*/
public void resetForTypeCheck() {
typesIndexedByProperty.clear();
eachRefTypeIndexedByProperty.clear();
initializeBuiltInTypes();
namesToTypes.clear();
namespaces.clear();
initializeRegistry();
}
private void initializeBuiltInTypes() {
// These locals shouldn't be all caps.
BooleanType BOOLEAN_TYPE = new BooleanType(this);
registerNativeType(JSTypeNative.BOOLEAN_TYPE, BOOLEAN_TYPE);
NullType NULL_TYPE = new NullType(this);
registerNativeType(JSTypeNative.NULL_TYPE, NULL_TYPE);
NumberType NUMBER_TYPE = new NumberType(this);
registerNativeType(JSTypeNative.NUMBER_TYPE, NUMBER_TYPE);
StringType STRING_TYPE = new StringType(this);
registerNativeType(JSTypeNative.STRING_TYPE, STRING_TYPE);
UnknownType UNKNOWN_TYPE = new UnknownType(this, false);
registerNativeType(JSTypeNative.UNKNOWN_TYPE, UNKNOWN_TYPE);
registerNativeType(
JSTypeNative.CHECKED_UNKNOWN_TYPE, new UnknownType(this, true));
VoidType VOID_TYPE = new VoidType(this);
registerNativeType(JSTypeNative.VOID_TYPE, VOID_TYPE);
AllType ALL_TYPE = new AllType(this);
registerNativeType(JSTypeNative.ALL_TYPE, ALL_TYPE);
// Top Level Prototype (the One)
// The initializations of TOP_LEVEL_PROTOTYPE and OBJECT_FUNCTION_TYPE
// use each other's results, so at least one of them will get null
// instead of an actual type; however, this seems to be benign.
PrototypeObjectType TOP_LEVEL_PROTOTYPE =
new PrototypeObjectType(this, null, null, true);
registerNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE, TOP_LEVEL_PROTOTYPE);
// Object
FunctionType OBJECT_FUNCTION_TYPE =
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Native.NULL_TYPE));
register(getNativeType(JSTypeNative.NULL_TYPE), "Null");
register(getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE));
register(getNativeType(JSTypeNative.NUMBER_TYPE));
register(getNativeType(JSTypeNative.OBJECT_TYPE));
register(getNativeType(JSTypeNative.ERROR_TYPE));
register(getNativeType(JSTypeNative.URI_ERROR_TYPE));
register(getNativeType(JSTypeNative.EVAL_ERROR_TYPE));
register(getNativeType(JSTypeNative.TYPE_ERROR_TYPE));
register(getNativeType(JSTypeNative.RANGE_ERROR_TYPE));
register(getNativeType(JSTypeNative.REFERENCE_ERROR_TYPE));
register(getNativeType(JSTypeNative.SYNTAX_ERROR_TYPE));
register(getNativeType(JSTypeNative.REGEXP_TYPE));
register(getNativeType(JSTypeNative.STRING_OBJECT_TYPE));
register(getNativeType(JSTypeNative.STRING_TYPE));
register(getNativeType(JSTypeNative.VOID_TYPE));
register(getNativeType(JSTypeNative.VOID_TYPE), "Undefined");
register(getNativeType(JSTypeNative.VOID_TYPE), "void");
register(getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), "Function");
}
private void register(JSType type) {
register(type, type.toString());
}
private void register(JSType type, String name) {
namesToTypes.put(name, type);
// Add all the namespaces in which this name lives.
while (name.indexOf('.') > 0) {
name = name.substring(0, name.lastIndexOf('.'));
namespaces.add(name);
}
}
private void registerNativeType(JSTypeNative typeId, JSType type) {
nativeTypes[typeId.ordinal()] = type;
}
/**
* Tells the type system that {@code owner} may have a property named
* {@code propertyName}. This allows the registry to keep track of what
* types a property is defined upon.
*
* This is NOT the same as saying that {@code owner} must have a property
* named type. ObjectType#hasProperty attempts
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> must return
* {@code [Object, Array]}. It would not be correct to collapse them to
* {@code [Object]}.
*/
public Iterable<ObjectType> getEachReferenceTypeWithProperty(
String propertyName) {
if (eachRefTypeIndexedByProperty.containsKey(propertyName)) {
return eachRefTypeIndexedByProperty.get(propertyName).values();
} else {
return ImmutableList.of();
}
}
/**
* Finds the common supertype of the two given object types.
*/
ObjectType findCommonSuperObject(ObjectType a, ObjectType b) {
List<ObjectType> stackA = getSuperStack(a);
List<ObjectType> stackB = getSuperStack(b);
ObjectType result = getNativeObjectType(JSTypeNative.OBJECT_TYPE);
while (!stackA.isEmpty() && !stackB.isEmpty()) {
ObjectType currentA = stackA.remove(stackA.size() - 1);
ObjectType currentB = stackB.remove(stackB.size() - 1);
if (currentA.isEquivalentTo(currentB)) {
result = currentA;
} else {
return result;
}
}
return result;
}
private static List<ObjectType> getSuperStack(ObjectType a) {
List<ObjectType> stack = Lists.newArrayListWithExpectedSize(5);
for (ObjectType current = a;
current != null;
current = current.getImplicitPrototype()) {
stack.add(current);
}
return stack;
}
/**
* Increments the current generation. Clients must call this in order to
* move to the next generation of type resolution, allowing types to attempt
* resolution again.
*/
public void incrementGeneration() {
for (NamedType type : resolvedNamedTypes.values()) {
type.clearResolved();
}
unresolvedNamedTypes.putAll(resolvedNamedTypes);
resolvedNamedTypes.clear();
}
boolean isLastGeneration() {
return lastGeneration;
}
/**
* Sets whether this is the last generation. In the last generation,
* {@link NamedType} warns about unresolved types.
*/
public void setLastGeneration(boolean lastGeneration) {
this.lastGeneration = lastGeneration;
}
/**
* Tells the type system that {@code type} implements interface {@code
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> * InterfaceInstance}.
* {@code inter} must be an ObjectType for the instance of the interface as it
* could be a named type and not yet have the constructor.
*/
void registerTypeImplementingInterface(
FunctionType type, ObjectType interfaceInstance) {
interfaceToImplementors.put(interfaceInstance.getReferenceName(), type);
}
/**
* Returns a collection of types that directly implement {@code
* interfaceInstance}. Subtypes of implementing types are not guaranteed to
* be returned. {@code interfaceInstance} must be an ObjectType for the
* instance of the interface.
*/
public Collection<FunctionType> getDirectImplementors(
ObjectType interfaceInstance) {
return interfaceToImplementors.get(interfaceInstance.getReferenceName());
}
/**
* Records declared global type names. This makes resolution faster
* and more robust in the common case.
*
* @param name The name of the type to be recorded.
* @param t The actual type being associated with the name.
* @return True if this name is not already defined, false otherwise.
*/
public boolean declareType(String name, JSType t) {
if (namesToTypes.containsKey(name)) {
return false;
}
register(t, name);
return true;
}
/**
* Overrides a declared global type name. Throws an exception if this
* type name hasn't been declared yet.
*/
public void overwriteDeclaredType(String name, JSType t) {
Preconditions.checkState(namesToTypes.containsKey(name));
register(t, name);
}
/**
* Records a forward-declared type name. We will not emit errors if this
* type name never resolves to anything.
*/
public void forwardDeclareType(String name) {
forwardDeclaredTypes.add(name);
}
/**
* Whether this is a forward-declared type name.
*/
public boolean isForwardDeclaredType(String name) {
return forwardDeclaredTypes.contains(name);
}
/** Determines whether the given JS package exists. */
public boolean hasNamespace(String name) {
return namespaces.contains(name);
}
/**
* Looks up a type by name.
*
* @param jsTypeName The name string.
* @return the corresponding JSType object or {@code null} it cannot be
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> found
*/
public JSType getType(String jsTypeName) {
// TODO(user): Push every local type name out of namesToTypes so that
// NamedType#resolve is correct.
if (jsTypeName.equals(templateTypeName)) {
return templateType;
}
return namesToTypes.get(jsTypeName);
}
public JSType getNativeType(JSTypeNative typeId) {
return nativeTypes[typeId.ordinal()];
}
public ObjectType getNativeObjectType(JSTypeNative typeId) {
return (ObjectType) getNativeType(typeId);
}
public FunctionType getNativeFunctionType(JSTypeNative typeId) {
return (FunctionType) getNativeType(typeId);
}
/**
* Looks up a type by name. To allow for forward references to types, an
* unrecognized string has to be bound to a NamedType object that will be
* resolved later.
*
* @param scope A scope for doing type name resolution.
* @param jsTypeName The name string.
* @param sourceName The name of the source file where this reference appears.
* @param lineno The line number of the reference.
* @return a NamedType if the string argument is not one of the known types,
* otherwise the corresponding JSType object.
*/
public JSType getType(StaticScope<JSType> scope, String jsTypeName,
String sourceName, int lineno, int charno) {
JSType type = getType(jsTypeName);
if (type == null) {
// TODO(user): Each instance should support named type creation using
// interning.
NamedType namedType =
new NamedType(this, jsTypeName, sourceName, lineno, charno);
unresolvedNamedTypes.put(scope, namedType);
type = namedType;
}
return type;
}
/**
* Flushes out the current resolved and unresovled Named Types from
* the type registry. This is intended to be used ONLY before a
* compile is run.
*/
public void clearNamedTypes() {
resolvedNamedTypes.clear();
unresolvedNamedTypes.clear();
}
/**
* Resolve all the unresolved types in the given scope.
*/
public void resolveTypesInScope(StaticScope<JSType> scope) {
for (NamedType
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>
/**
* Creates a named type.
*/
@VisibleForTesting
public JSType createNamedType(String reference,
String sourceName, int lineno, int charno) {
return new NamedType(this, reference, sourceName, lineno, charno);
}
/**
* Identifies the name of a typedef or enum before we actually declare it.
*/
public void identifyNonNullableName(String name) {
Preconditions.checkNotNull(name);
nonNullableTypeNames.add(name);
}
/**
* Creates a JSType from the nodes representing a type.
* @param n The node with type info.
* @param sourceName The source file name.
* @param scope A scope for doing type name lookups.
*/
public JSType createFromTypeNodes(Node n, String sourceName,
StaticScope<JSType> scope) {
if (resolveMode == ResolveMode.LAZY_EXPRESSIONS) {
// If the type expression doesn't contain any names, just
// resolve it anyway.
boolean hasNames = hasTypeName(n);
if (hasNames) {
return new UnresolvedTypeExpression(this, n, sourceName);
}
}
return createFromTypeNodesInternal(n, sourceName, scope);
}
private boolean hasTypeName(Node n) {
if (n.getType() == Token.STRING) {
return true;
}
for (Node child = n.getFirstChild();
child != null; child = child.getNext()) {
if (hasTypeName(child)) {
return true;
}
}
return false;
}
/** @see #createFromTypeNodes(Node, String, StaticScope) */
private JSType createFromTypeNodesInternal(Node n, String sourceName,
StaticScope<JSType> scope) {
switch (n.getType()) {
case Token.LC: // Record type.
return createRecordTypeFromNodes(
n.getFirstChild(), sourceName, scope);
case Token.BANG: // Not nullable
return createFromTypeNodesInternal(
n.getFirstChild(), sourceName, scope)
.restrictByNotNullOrUndefined();
case Token.QMARK: // Nullable or unknown
Node firstChild = n.getFirstChild();
if (firstChild == null) {
return getNativeType(UNKNOWN_TYPE
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> {
return (bitset & mask) != 0x00;
}
// Visible for testing.
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
private void lazyInitInfo() {
if (info == null) {
info = new LazilyInitializedInfo();
}
}
/**
* Lazily initializes the documentation information object, but only
* if the JSDocInfo was told to keep such information around.
*/
private boolean lazyInitDocumentation() {
if (!includeDocumentation) {
return false;
}
if (documentation == null) {
documentation = new LazilyInitializedDocumentation();
}
return true;
}
/**
* Adds a marker to the documentation (if it exists) and
* returns the marker. Returns null otherwise.
*/
Marker addMarker() {
if (!lazyInitDocumentation()) {
return null;
}
if (documentation.markers == null) {
documentation.markers = Lists.newArrayList();
}
Marker marker = new Marker();
documentation.markers.add(marker);
return marker;
}
/**
* Sets the deprecation reason.
*
* @param reason The deprecation reason
*/
boolean setDeprecationReason(String reason) {
lazyInitInfo();
if (info.deprecated != null) {
return false;
}
info.deprecated = reason;
return true;
}
/**
* Add a suppressed warning.
*/
public void addSuppression(String suppression) {
lazyInitInfo();
if (info.suppressions == null) {
info.suppressions = Sets.newHashSet();
}
info.suppressions.add(suppression);
}
/**
* Sets suppressed warnings.
* @param suppressions A list of suppressed warning types.
*/
boolean setSuppressions(Set<String> suppressions) {
lazyInitInfo();
if (info.suppressions != null) {
return false;
}
info.suppressions = suppressions;
return true;
}
/**
* Add modifies values.
*/
void addModifies(String modifies) {
lazyInitInfo();
if (info.modifies == null) {
info.modifies = Sets.newHashSet();
}
info.modifies
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>.add(modifies);
}
/**
* Sets modifies values.
* @param modifies A list of modifies types.
*/
boolean setModifies(Set<String> modifies) {
lazyInitInfo();
if (info.modifies != null) {
return false;
}
info.modifies = modifies;
return true;
}
/**
* Documents the version.
*/
boolean documentVersion(String version) {
if (!lazyInitDocumentation()) {
return true;
}
if (documentation.version != null) {
return false;
}
documentation.version = version;
return true;
}
/**
* Documents a reference (i.e. adds a "see" reference to the list).
*/
boolean documentReference(String reference) {
if (!lazyInitDocumentation()) {
return true;
}
if (documentation.sees == null) {
documentation.sees = Lists.newArrayList();
}
documentation.sees.add(reference);
return true;
}
/**
* Documents the author (i.e. adds it to the author list).
*/
boolean documentAuthor(String author) {
if (!lazyInitDocumentation()) {
return true;
}
if (documentation.authors == null) {
documentation.authors = Lists.newArrayList();
}
documentation.authors.add(author);
return true;
}
/**
* Documents the throws (i.e. adds it to the throws list).
*/
boolean documentThrows(JSTypeExpression type, String throwsDescription) {
if (!lazyInitDocumentation()) {
return true;
}
if (documentation.throwsDescriptions == null) {
documentation.throwsDescriptions =
new LinkedHashMap<JSTypeExpression, String>();
}
if (!documentation.throwsDescriptions.containsKey(type)) {
documentation.throwsDescriptions.put(type, throwsDescription);
return true;
}
return false;
}
/**
* Documents a parameter. Parameters are described using the {@code @param}
* annotation.
*
* @param parameter the parameter's name
* @param description the parameter's description
*/
boolean documentParam(String parameter, String description) {
if (!lazyInitDocumentation()) {
return true;
}
if (documentation.parameters == null) {
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> name.
*/
boolean declareTemplateTypeName(String templateTypeName) {
lazyInitInfo();
if (info.templateTypeName != null) {
return false;
}
info.templateTypeName = templateTypeName;
return true;
}
/**
* Declares that the method throws a given type.
*
* @param jsType The type that can be thrown by the method.
*/
boolean declareThrows(JSTypeExpression jsType) {
lazyInitInfo();
if (info.thrownTypes == null) {
info.thrownTypes = Lists.newArrayList();
}
info.thrownTypes.add(jsType);
return true;
}
/**
* Gets the visibility specified by {@code @private}, {@code @protected} or
* {@code @public} annotation. If no visibility is specified, visibility
* is inherited from the base class.
*/
public Visibility getVisibility() {
return visibility;
}
/**
* Gets the parameter type.
* @param parameter the parameter's name
* @return the parameter's type or {@code null} if this parameter is not
* defined or has a {@code null} type
*/
public JSTypeExpression getParameterType(String parameter) {
if (info == null || info.parameters == null) {
return null;
}
return info.parameters.get(parameter);
}
/**
* Returns whether the parameter is defined.
*/
public boolean hasParameter(String parameter) {
if (info == null || info.parameters == null) {
return false;
}
return info.parameters.containsKey(parameter);
}
/**
* Returns whether the parameter has an attached type.
*
* @return {@code true} if the parameter has an attached type, {@code false}
* if the parameter has no attached type or does not exist.
*/
public boolean hasParameterType(String parameter) {
return getParameterType(parameter) != null;
}
/**
* Returns the set of names of the defined parameters. The iteration order
* of the returned set is not the order in which parameters are defined.
*
* @return the set of names of the defined parameters. The returned set is
* immutable.
*/
public Set<String> getParameterNames() {
if (info == null || info.
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> * Adds an implemented interface. Returns whether the interface was added. If
* the interface was already present in the list, it won't get added again.
*/
boolean addImplementedInterface(JSTypeExpression interfaceName) {
lazyInitInfo();
if (info.implementedInterfaces == null) {
info.implementedInterfaces = Lists.newArrayListWithCapacity(2);
}
if (info.implementedInterfaces.contains(interfaceName)) {
return false;
}
info.implementedInterfaces.add(interfaceName);
return true;
}
/**
* Returns the types specified by the {@code @implements} annotation.
*
* @return An immutable list of JSTypeExpression objects that can
* be resolved to types.
*/
public List<JSTypeExpression> getImplementedInterfaces() {
if (info == null || info.implementedInterfaces == null) {
return ImmutableList.of();
}
return Collections.unmodifiableList(info.implementedInterfaces);
}
/**
* Gets the number of interfaces specified by the {@code @implements}
* annotation.
*/
public int getImplementedInterfaceCount() {
if (info == null || info.implementedInterfaces == null) {
return 0;
}
return info.implementedInterfaces.size();
}
/**
* Adds an extended interface (for interface only).
* Returns whether the type was added.
* if the type was already present in the list, it won't get added again.
*/
boolean addExtendedInterface(JSTypeExpression type) {
lazyInitInfo();
if (info.extendedInterfaces == null) {
info.extendedInterfaces = Lists.newArrayListWithCapacity(2);
}
if (info.extendedInterfaces.contains(type)) {
return false;
}
info.extendedInterfaces.add(type);
return true;
}
/**
* Returns the interfaces extended by an interface
*
* @return An immutable list of JSTypeExpression objects that can
* be resolved to types.
*/
public List<JSTypeExpression> getExtendedInterfaces() {
if (info == null || info.extendedInterfaces == null) {
return ImmutableList.of();
}
return Collections.unmodifiableList(info.extendedInterfaces);
}
/**
* Gets the number of extended interfaces specified
*/
public int getExtendedInterfacesCount() {
if (info
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Description() {
return documentation == null ? null : documentation.blockDescription;
}
/**
* Returns whether this has a fileoverview flag.
*/
public boolean hasFileOverview() {
return getFlag(MASK_FILEOVERVIEW);
}
/**
* Returns the file overview or null if none specified.
*/
public String getFileOverview() {
return documentation == null ? null : documentation.fileOverview;
}
public Node getAssociatedNode() {
return this.associatedNode;
}
/**
* Sets the node associated with this JSDoc.
* Notice that many nodes may have pointer to the same JSDocInfo
* object (because we propagate it across the type graph). But there
* is only one canonical "owner" node of the JSDocInfo, which corresponds
* to its original place in the syntax tree.
*/
public void setAssociatedNode(Node node) {
this.associatedNode = node;
}
/** Gets the name of the source file that contains this JSDoc. */
public String getSourceName() {
return this.associatedNode != null
? this.associatedNode.getSourceFileName() : null;
}
/** Gets the list of all markers for the documentation in this JSDoc. */
public Collection<Marker> getMarkers() {
return (documentation == null || documentation.markers == null)
? ImmutableList.<Marker>of() : documentation.markers;
}
/** Gets the template type name. */
public String getTemplateTypeName() {
if (info == null) {
return null;
}
return info.templateTypeName;
}
/**
* Returns a collection of all type nodes that are a part of this JSDocInfo.
* This includes @type, @this, @extends, @implements, @param, @throws,
* and @return. Any future type specific JSDoc should make sure to add the
* appropriate nodes here.
* @return collection of all type nodes
*/
public Collection<Node> getTypeNodes() {
List<Node> nodes = Lists.newArrayList();
if (type != null) {
nodes.add(type.getRoot());
}
if (thisType != null) {
nodes.add(thisType.getRoot());
}
if (info != null) {
if (info.baseType !=
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> null) {
nodes.add(info.baseType.getRoot());
}
if (info.extendedInterfaces != null) {
for (JSTypeExpression interfaceType : info.extendedInterfaces) {
nodes.add(interfaceType.getRoot());
}
}
if (info.implementedInterfaces != null) {
for (JSTypeExpression interfaceType : info.implementedInterfaces) {
nodes.add(interfaceType.getRoot());
}
}
if (info.parameters != null) {
for (JSTypeExpression parameterType : info.parameters.values()) {
if (parameterType != null) {
nodes.add(parameterType.getRoot());
}
}
}
if (info.thrownTypes != null) {
for (JSTypeExpression thrownType : info.thrownTypes) {
if (thrownType != null) {
nodes.add(thrownType.getRoot());
}
}
}
}
return nodes;
}
public boolean hasModifies() {
return info != null && info.modifies != null;
}
/**
* Returns the original JSDoc comment string. Returns null unless
* parseJsDocDocumentation is enabled via the ParserConfig.
*/
public String getOriginalCommentString() {
return documentation == null ? null : documentation.sourceComment;
}
void setOriginalCommentString(String sourceComment) {
if (!lazyInitDocumentation()) {
return;
}
documentation.sourceComment = sourceComment;
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>Pass()) {
loopStart = passName;
} else if (loopStart != null && pass.isOneTimePass()) {
graph.connect(lastPass, "loop", loopStart);
loopStart = null;
}
if (lastPass != null) {
graph.connect(lastPass, "", passName);
}
lastPass = passName;
}
return graph;
}
/**
* Create a type inference pass.
*/
final TypeInferencePass makeTypeInference(AbstractCompiler compiler) {
return new TypeInferencePass(
compiler, compiler.getReverseAbstractInterpreter(),
topScope, typedScopeCreator);
}
final InferJSDocInfo makeInferJsDocInfo(AbstractCompiler compiler) {
return new InferJSDocInfo(compiler);
}
/**
* Create a type-checking pass.
*/
final TypeCheck makeTypeCheck(AbstractCompiler compiler) {
return new TypeCheck(
compiler,
compiler.getReverseAbstractInterpreter(),
compiler.getTypeRegistry(),
topScope,
typedScopeCreator,
options.reportMissingOverride,
options.reportUnknownTypes)
.reportMissingProperties(options.enables(
DiagnosticGroup.forType(TypeCheck.INEXISTENT_PROPERTY)));
}
/**
* Insert the given pass factory before the factory of the given name.
*/
final static void addPassFactoryBefore(
List<PassFactory> factoryList, PassFactory factory, String passName) {
factoryList.add(
findPassIndexByName(factoryList, passName), factory);
}
/**
* Find a pass factory with the same name as the given one, and replace it.
*/
final static void replacePassFactory(
List<PassFactory> factoryList, PassFactory factory) {
factoryList.set(
findPassIndexByName(factoryList, factory.getName()), factory);
}
/**
* Throws an exception if no pass with the given name exists.
*/
private static int findPassIndexByName(
List<PassFactory> factoryList, String name) {
for (int i = 0; i < factoryList.size(); i++) {
if (factoryList.get(i).getName().equals(name)) {
return i;
}
}
throw new IllegalArgumentException(
"No factory named '" + name +
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> compilation job.
*
* This does not affect how we handle files that do not provide symbols.
* See setMoocherDropping for information on how these are handled.
*/
public void setDependencyPruning(boolean enabled) {
this.pruneDependencies = enabled;
}
/**
* Enables or disables moocher dropping mode.
*
* A 'moocher' is a file that does not provide any symbols (though they
* may require symbols). This is usually because they don't want to
* tie themselves to a particular dependency system (e.g., Closure's
* goog.provide, CommonJS modules). So they rely on other people to
* manage dependencies on them.
*
* If true, we drop these files when we prune dependencies.
* If false, we always keep these files an anything they depend on.
* The default is false.
*
* Notice that this option only makes sense if dependency pruning is on,
* and a set of entry points is specified.
*/
public void setMoocherDropping(boolean enabled) {
this.dropMoochers = enabled;
}
/**
* Adds a collection of symbols to always keep.
*
* In dependency pruning mode, we will automatically keep all the
* transitive dependencies of these symbols.
*
* The syntactic form of a symbol depends on the type of dependency
* primitives we're using. For example, goog.provide('foo.bar')
* provides the symbol 'foo.bar'.
*/
public void setEntryPoints(Collection<String> symbols) {
entryPoints.clear();
entryPoints.addAll(symbols);
}
/** Returns whether re-ordering of files is needed. */
boolean needsManagement() {
return sortDependencies || pruneDependencies;
}
boolean shouldSortDependencies() {
return sortDependencies;
}
boolean shouldPruneDependencies() {
return pruneDependencies;
}
boolean shouldDropMoochers() {
return pruneDependencies && dropMoochers;
}
Collection<String> getEntryPoints() {
return entryPoints;
}
}
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> Iterable<ObjectType> getAllImplementedInterfaces() {
// Store them in a linked hash set, so that the compile job is
// deterministic.
Set<ObjectType> interfaces = Sets.newLinkedHashSet();
for (ObjectType type : getImplementedInterfaces()) {
addRelatedInterfaces(type, interfaces);
}
return interfaces;
}
private void addRelatedInterfaces(ObjectType instance, Set<ObjectType> set) {
FunctionType constructor = instance.getConstructor();
if (constructor != null) {
if (!constructor.isInterface()) {
return;
}
set.add(instance);
for (ObjectType interfaceType : instance.getCtorExtendedInterfaces()) {
addRelatedInterfaces(interfaceType, set);
}
}
}
/** Returns interfaces implemented directly by a class or its superclass. */
public Iterable<ObjectType> getImplementedInterfaces() {
FunctionType superCtor = isConstructor() ?
getSuperClassConstructor() : null;
if (superCtor == null) {
return implementedInterfaces;
} else {
return Iterables.concat(
implementedInterfaces, superCtor.getImplementedInterfaces());
}
}
/** Returns interfaces directly implemented by the class. */
public Iterable<ObjectType> getOwnImplementedInterfaces() {
return implementedInterfaces;
}
public void setImplementedInterfaces(List<ObjectType> implementedInterfaces) {
// Records this type for each implemented interface.
for (ObjectType type : implementedInterfaces) {
registry.registerTypeImplementingInterface(this, type);
}
this.implementedInterfaces = ImmutableList.copyOf(implementedInterfaces);
}
/**
* Returns all extended interfaces declared by an interfaces or its super-
* interfaces. If this is called before all types are resolved, it may return
* an incomplete set.
*/
public Iterable<ObjectType> getAllExtendedInterfaces() {
// Store them in a linked hash set, so that the compile job is
// deterministic.
Set<ObjectType> extendedInterfaces = Sets.newLinkedHashSet();
for (ObjectType interfaceType : getExtendedInterfaces()) {
addRelatedExtendedInterfaces(interfaceType, extendedInterfaces);
}
return extendedInterfaces;
}
private void addRelatedExtendedInterfaces(ObjectType instance,
Set<ObjectType> set) {
FunctionType constructor = instance.getConstructor();
if (constructor != null) {
set.add(instance);
for (ObjectType interfaceType : constructor.get
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS> }
/**
* Sets the instance type. This should only be used for special
* native types.
*/
void setInstanceType(ObjectType instanceType) {
typeOfThis = instanceType;
}
/**
* Returns whether this function type has an instance type.
*/
public boolean hasInstanceType() {
return isConstructor() || isInterface();
}
/**
* Gets the type of {@code this} in this function.
*/
@Override
public ObjectType getTypeOfThis() {
return typeOfThis.isNoObjectType() ?
registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE) : typeOfThis;
}
/**
* Gets the source node or null if this is an unknown function.
*/
public Node getSource() {
return source;
}
/**
* Sets the source node.
*/
public void setSource(Node source) {
if (prototypeSlot != null) {
// NOTE(bashir): On one hand when source is null we want to drop any
// references to old nodes retained in prototypeSlot. On the other hand
// we cannot simply drop prototypeSlot, so we retain all information
// except the propertyNode for which we use an approximation! These
// details mostly matter in hot-swap passes.
if (source == null || prototypeSlot.getNode() == null) {
prototypeSlot = new Property(prototypeSlot.getName(),
prototypeSlot.getType(), prototypeSlot.isTypeInferred(), source);
}
}
this.source = source;
}
/** Adds a type to the list of subtypes for this type. */
private void addSubType(FunctionType subType) {
if (subTypes == null) {
subTypes = Lists.newArrayList();
}
subTypes.add(subType);
}
@Override
public void clearCachedValues() {
super.clearCachedValues();
if (subTypes != null) {
for (FunctionType subType : subTypes) {
subType.clearCachedValues();
}
}
if (!isNativeObjectType()) {
if (hasInstanceType()) {
getInstanceType().clearCachedValues();
}
if (prototypeSlot != null) {
((PrototypeObjectType) prototypeSlot.getType()).clearCachedValues();
}
}
}
/**
* Returns a list of types that are subtypes of this type
Closure, 43
<FILEB>
<CHANGES>
private List<Node> lentObjectLiterals = null;
<CHANGEE>
<CHANGES>
if (n.getParent()!= null && NodeUtil.isStatement(n) &&
lentObjectLiterals!= null) {
for (Node objLit : lentObjectLiterals) {
defineObjectLiteral(objLit);
}
lentObjectLiterals.clear();
}
<CHANGEE>
<CHANGES>
JSDocInfo info = n.getJSDocInfo();
if (info!= null &&
info.getLendsName()!= null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<FILEE>
<FILEB>
*/
final Scope scope;
private final List<DeferredSetType> deferredSetTypes =
Lists.newArrayList();
/**
* Functions that we found in the global scope and not in externs.
*/
private final List<Node> nonExternFunctions = Lists.newArrayList();
/**
* Object literals with a @lends annotation aren't analyzed until we
* reach the root of the statement they're defined in.
*
* This ensures that if there are any @lends annotations on the object
* literals, the type on the @lends annotation resolves correctly.
*
* For more information, see
* http://code.google.com/p/closure-compiler/issues/detail?id=314
*/
<CHANGES>
<CHANGEE>
/**
* Type-less stubs.
*
* If at the end of traversal, we still don't have types for these
* stubs, then we should declare UNKNOWN types.
*/
private final List<StubDeclaration> stubDeclarations =
Lists.newArrayList();
/**
* The current source file that we're in.
*/
private String sourceName = null;
firstChild, n, firstChild.getNext());
}
break;
case Token.CATCH:
defineCatch(n, parent);
break;
case Token.VAR:
defineVar(n, parent);
break;
case Token.GETPROP:
// Handle stubbed properties.
if (parent.isExprResult() &&
n.isQualifiedName()) {
maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
}
break;
}
// Analyze any @lends object literals in this statement.
<CHANGES>
<CHANGEE>
}
private void attachLiteralTypes(NodeTraversal t, Node n) {
switch (n.getType()) {
case Token.NULL:
n.setJSType(getNativeType(NULL_TYPE));
break;
case Token.VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(STRING_TYPE));
}
break;
case Token.NUMBER:
n.set<SCANS>. This is only valid
* for constructor functions, and may be null. This allows a downward
* traversal of the subtype graph.
*/
public List<FunctionType> getSubTypes() {
return subTypes;
}
@Override
public boolean hasCachedValues() {
return prototypeSlot != null || super.hasCachedValues();
}
/**
* Gets the template type name.
*/
public String getTemplateTypeName() {
return templateTypeName;
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
setResolvedTypeInternal(this);
call = (ArrowType) safeResolve(call, t, scope);
if (prototypeSlot != null) {
prototypeSlot.setType(
safeResolve(prototypeSlot.getType(), t, scope));
}
// Warning about typeOfThis if it doesn't resolve to an ObjectType
// is handled further upstream.
//
// TODO(nicksantos): Handle this correctly if we have a UnionType.
//
// TODO(nicksantos): In ES3, the runtime coerces "null" to the global
// activation object. In ES5, it leaves it as null. Just punt on this
// issue for now by coercing out null. This is complicated by the
// fact that when most people write @this {Foo}, they really don't
// mean "nullable Foo". For certain tags (like @extends) we de-nullify
// the name for them.
JSType maybeTypeOfThis = safeResolve(typeOfThis, t, scope);
if (maybeTypeOfThis != null) {
maybeTypeOfThis = maybeTypeOfThis.restrictByNotNullOrUndefined();
}
if (maybeTypeOfThis instanceof ObjectType) {
typeOfThis = (ObjectType) maybeTypeOfThis;
}
boolean changed = false;
ImmutableList.Builder<ObjectType> resolvedInterfaces =
ImmutableList.builder();
for (ObjectType iface : implementedInterfaces) {
ObjectType resolvedIface = (ObjectType) iface.resolve(t, scope);
resolvedInterfaces.add(resolvedIface);
changed |= (resolvedIface != iface);
}
if (changed) {
implementedInterfaces = resolvedInterfaces.build();
}
if (subTypes != null) {
for (int i = 0; i < subTypes.size(); i++)